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 unsigned char rid_fps_to_vic(unsigned char rid
, unsigned fps
)
310 for (unsigned i
= 1; i
< ARRAY_SIZE(vf_rate_values
); i
++) {
311 if (vf_rate_values
[i
] == fps
)
312 return rid2vic
[rid
][i
- 1];
317 const struct timings
*cta_close_match_to_vic(const timings
&t
, unsigned &vic
)
319 for (vic
= 1; vic
<= ARRAY_SIZE(edid_cta_modes1
); vic
++) {
320 if (timings_close_match(t
, edid_cta_modes1
[vic
- 1]))
321 return &edid_cta_modes1
[vic
- 1];
323 for (vic
= 193; vic
< ARRAY_SIZE(edid_cta_modes2
) + 193; vic
++) {
324 if (timings_close_match(t
, edid_cta_modes1
[vic
- 193]))
325 return &edid_cta_modes1
[vic
- 193];
331 bool cta_matches_vic(const timings
&t
, unsigned &vic
)
333 for (vic
= 1; vic
<= ARRAY_SIZE(edid_cta_modes1
); vic
++) {
334 if (match_timings(t
, edid_cta_modes1
[vic
- 1]))
337 for (vic
= 193; vic
< ARRAY_SIZE(edid_cta_modes2
) + 193; vic
++) {
338 if (match_timings(t
, edid_cta_modes1
[vic
- 193]))
345 void edid_state::cta_list_vics()
348 for (unsigned vic
= 1; vic
<= ARRAY_SIZE(edid_cta_modes1
); vic
++) {
349 sprintf(type
, "VIC %3u", vic
);
350 print_timings("", &edid_cta_modes1
[vic
- 1], type
, "", false, false);
352 for (unsigned vic
= 193; vic
< ARRAY_SIZE(edid_cta_modes2
) + 193; vic
++) {
353 sprintf(type
, "VIC %3u", vic
);
354 print_timings("", &edid_cta_modes2
[vic
- 193], type
, "", false, false);
358 void edid_state::cta_list_hdmi_vics()
360 for (unsigned i
= 0; i
< ARRAY_SIZE(edid_hdmi_mode_map
); i
++) {
361 unsigned vic
= edid_hdmi_mode_map
[i
];
364 sprintf(type
, "HDMI VIC %u", i
+ 1);
365 print_timings("", find_vic_id(vic
), type
, "", false, false);
369 void edid_state::cta_list_rids()
371 for (unsigned i
= 1; i
< ARRAY_SIZE(rids
); i
++) {
372 printf("RID %2u: %5ux%-4u %2u:%-2u\n", i
,
373 rids
[i
].hact
, rids
[i
].vact
,
374 rids
[i
].hratio
, rids
[i
].vratio
);
378 void edid_state::cta_list_rid_timings(unsigned list_rid
)
380 for (unsigned rid
= 1; rid
< ARRAY_SIZE(rids
); rid
++) {
383 if (list_rid
&& rid
!= list_rid
)
386 sprintf(type
, "RID %u", rid
);
387 for (unsigned i
= 1; i
< ARRAY_SIZE(vf_rate_values
); i
++) {
388 unsigned fps
= vf_rate_values
[i
];
390 if (rid_to_vic(rid
, i
)) {
391 printf("%s: %5ux%-4u %7.3f Hz %3u:%-2u maps to VIC %u\n", type
,
392 rids
[rid
].hact
, rids
[rid
].vact
, (double)fps
,
393 rids
[rid
].hratio
, rids
[rid
].vratio
,
397 timings t
= calc_ovt_mode(rids
[rid
].hact
, rids
[rid
].vact
,
398 rids
[rid
].hratio
, rids
[rid
].vratio
, fps
);
399 print_timings("", &t
, type
, "", false, false);
404 static std::string
audio_ext_format(unsigned char x
)
406 if (x
>= 1 && x
<= 3)
407 fail("Obsolete Audio Ext Format 0x%02x.\n", x
);
409 case 1: return "HE AAC (Obsolete)";
410 case 2: return "HE AAC v2 (Obsolete)";
411 case 3: return "MPEG Surround (Obsolete)";
412 case 4: return "MPEG-4 HE AAC";
413 case 5: return "MPEG-4 HE AAC v2";
414 case 6: return "MPEG-4 AAC LC";
415 case 7: return "DRA";
416 case 8: return "MPEG-4 HE AAC + MPEG Surround";
417 case 10: return "MPEG-4 AAC LC + MPEG Surround";
418 case 11: return "MPEG-H 3D Audio";
419 case 12: return "AC-4";
420 case 13: return "L-PCM 3D Audio";
421 case 14: return "Auro-Cx";
422 case 15: return "MPEG-D USAC";
425 fail("Unknown Audio Ext Format 0x%02x.\n", x
);
426 return std::string("Unknown Audio Ext Format (") + utohex(x
) + ")";
429 static std::string
audio_format(unsigned char x
)
432 case 1: return "Linear PCM";
433 case 2: return "AC-3";
434 case 3: return "MPEG 1 (Layers 1 & 2)";
435 case 4: return "MPEG 1 Layer 3 (MP3)";
436 case 5: return "MPEG2 (multichannel)";
437 case 6: return "AAC LC";
438 case 7: return "DTS";
439 case 8: return "ATRAC";
440 case 9: return "One Bit Audio";
441 case 10: return "Enhanced AC-3 (DD+)";
442 case 11: return "DTS-HD";
443 case 12: return "MAT (MLP)";
444 case 13: return "DST";
445 case 14: return "WMA Pro";
448 fail("Unknown Audio Format 0x%02x.\n", x
);
449 return std::string("Unknown Audio Format (") + utohex(x
) + ")";
452 static std::string
mpeg_h_3d_audio_level(unsigned char x
)
455 case 0: return "Unspecified";
456 case 1: return "Level 1";
457 case 2: return "Level 2";
458 case 3: return "Level 3";
459 case 4: return "Level 4";
460 case 5: return "Level 5";
463 fail("Unknown MPEG-H 3D Audio Level 0x%02x.\n", x
);
464 return std::string("Unknown MPEG-H 3D Audio Level (") + utohex(x
) + ")";
467 static void cta_audio_block(const unsigned char *x
, unsigned length
)
469 unsigned i
, format
, ext_format
;
472 fail("Broken CTA-861 audio block length %d.\n", length
);
476 for (i
= 0; i
< length
; i
+= 3) {
477 format
= (x
[i
] & 0x78) >> 3;
479 printf(" Reserved (0x00)\n");
480 fail("Audio Format Code 0x00 is reserved.\n");
485 printf(" %s:\n", audio_format(format
).c_str());
487 ext_format
= (x
[i
+ 2] & 0xf8) >> 3;
488 printf(" %s:\n", audio_ext_format(ext_format
).c_str());
491 printf(" Max channels: %u\n", (x
[i
] & 0x07)+1);
492 else if (ext_format
== 11)
493 printf(" MPEG-H 3D Audio Level: %s\n",
494 mpeg_h_3d_audio_level(x
[i
] & 0x07).c_str());
495 else if (ext_format
== 13)
496 printf(" Max channels: %u\n",
497 (((x
[i
+ 1] & 0x80) >> 3) | ((x
[i
] & 0x80) >> 4) |
499 else if ((ext_format
== 12 || ext_format
== 14) && (x
[i
] & 0x07))
500 fail("Bits F10-F12 must be 0.\n");
502 printf(" Max channels: %u\n", (x
[i
] & 0x07)+1);
504 if ((format
== 1 || format
== 14) && (x
[i
+ 2] & 0xf8))
505 fail("Bits F33-F37 must be 0.\n");
506 if (ext_format
!= 13 && (x
[i
+1] & 0x80))
507 fail("Bit F27 must be 0.\n");
509 // Several sample rates are not supported in certain formats
510 if (ext_format
== 12 && (x
[i
+1] & 0x29))
511 fail("Bits F20, F23 and F25 must be 0.\n");
512 if (ext_format
>= 4 && ext_format
<= 6 && (x
[i
+1] & 0x60))
513 fail("Bits F25 and F26 must be 0.\n");
514 if ((ext_format
== 8 || ext_format
== 10 || ext_format
== 15) && (x
[i
+1] & 0x60))
515 fail("Bits F25 and F26 must be 0.\n");
517 printf(" Supported sample rates (kHz):%s%s%s%s%s%s%s\n",
518 (x
[i
+1] & 0x40) ? " 192" : "",
519 (x
[i
+1] & 0x20) ? " 176.4" : "",
520 (x
[i
+1] & 0x10) ? " 96" : "",
521 (x
[i
+1] & 0x08) ? " 88.2" : "",
522 (x
[i
+1] & 0x04) ? " 48" : "",
523 (x
[i
+1] & 0x02) ? " 44.1" : "",
524 (x
[i
+1] & 0x01) ? " 32" : "");
525 if (format
== 1 || ext_format
== 13) {
526 printf(" Supported sample sizes (bits):%s%s%s\n",
527 (x
[i
+2] & 0x04) ? " 24" : "",
528 (x
[i
+2] & 0x02) ? " 20" : "",
529 (x
[i
+2] & 0x01) ? " 16" : "");
530 } else if (format
<= 8) {
531 printf(" Maximum bit rate: %u kb/s\n", x
[i
+2] * 8);
532 } else if (format
== 10) {
533 // As specified by the "Dolby Audio and Dolby Atmos over HDMI"
534 // specification (v1.0).
536 printf(" Supports Joint Object Coding\n");
538 printf(" Supports Joint Object Coding with ACMOD28\n");
539 } else if (format
== 11) {
540 // Reverse engineering, see:
541 // https://www.avsforum.com/threads/lg-c9-earc-info-thread.3072900/post-61795538
543 printf(" Supports DTS:X\n");
544 // Note: I strongly suspect that bit 0 indicates DTS-HD MA support.
545 printf(" Audio Format Code dependent value: 0x%02x\n", x
[i
+2]);
546 } else if (format
== 12) {
548 printf(" Supports Dolby TrueHD, object audio PCM and channel-based PCM\n");
549 printf(" Hash calculation %srequired for object audio PCM or channel-based PCM\n",
550 (x
[i
+2] & 2) ? "not " : "");
552 printf(" Supports only Dolby TrueHD\n");
554 } else if (format
== 14) {
555 printf(" Profile: %u\n", x
[i
+2] & 7);
556 } else if (format
>= 9 && format
<= 13) {
557 printf(" Audio Format Code dependent value: 0x%02x\n", x
[i
+2]);
558 } else if (ext_format
== 11 && (x
[i
+2] & 1)) {
559 printf(" Supports MPEG-H 3D Audio Low Complexity Profile\n");
560 } else if ((ext_format
>= 4 && ext_format
<= 6) ||
561 ext_format
== 8 || ext_format
== 10) {
562 printf(" AAC audio frame lengths:%s%s\n",
563 (x
[i
+2] & 4) ? " 1024_TL" : "",
564 (x
[i
+2] & 2) ? " 960_TL" : "");
565 if (ext_format
>= 8 && (x
[i
+2] & 1))
566 printf(" Supports %s signaled MPEG Surround data\n",
567 (x
[i
+2] & 1) ? "implicitly and explicitly" : "only implicitly");
568 if (ext_format
== 6 && (x
[i
+2] & 1))
569 printf(" Supports 22.2ch System H\n");
570 } else if (ext_format
== 12 || ext_format
== 14) {
571 printf(" Audio Format Code dependent value: %u\n", x
[i
+2] & 7);
576 void edid_state::cta_svd(const unsigned char *x
, unsigned n
, bool for_ycbcr420
)
578 bool ascending
= !for_ycbcr420
;
579 unsigned char last_vic
= 0;
580 bool first_vic_is_1_to_4
= false;
581 bool have_vics_5_and_up
= false;
584 for (i
= 0; i
< n
; i
++) {
585 const struct timings
*t
= NULL
;
586 unsigned char svd
= x
[i
];
587 unsigned char native
;
590 if ((svd
& 0x7f) == 0)
593 if ((svd
- 1) & 0x40) {
596 if (cta
.avi_version
== 2)
604 first_vic_is_1_to_4
= vic
<= 4;
606 have_vics_5_and_up
= true;
611 t
= find_vic_id(vic
);
615 cta
.supported_hdmi_vic_vsb_codes
|= 1 << 0;
618 cta
.supported_hdmi_vic_vsb_codes
|= 1 << 1;
621 cta
.supported_hdmi_vic_vsb_codes
|= 1 << 2;
624 cta
.supported_hdmi_vic_vsb_codes
|= 1 << 3;
627 bool first_svd
= cta
.first_svd
&& !for_ycbcr420
;
630 sprintf(type
, "VIC %3u", vic
);
631 const char *flags
= native
? "native" : "";
634 struct timings tmp
= *t
;
636 print_timings(" ", &tmp
, type
, flags
);
637 cta
.has_ycbcr420
= true;
639 print_timings(" ", t
, type
, flags
);
641 if (first_svd
&& !cta
.preferred_timings
.empty()) {
642 if (!match_timings(cta
.preferred_timings
[0].t
, *t
))
643 warn("VIC %u and the first DTD are not identical. Is this intended?\n", vic
);
644 else if (cta
.first_svd_might_be_preferred
)
645 warn("For improved preferred timing interoperability, set 'Native detailed modes' to 1.\n");
648 if (cta
.first_svd_might_be_preferred
)
649 cta
.preferred_timings
.insert(cta
.preferred_timings
.begin(),
650 timings_ext(*t
, type
, flags
));
652 cta
.preferred_timings
.push_back(timings_ext(*t
, type
, flags
));
655 cta
.first_svd
= false;
656 cta
.first_svd_might_be_preferred
= false;
659 cta
.native_timings
.push_back(timings_ext(*t
, type
, flags
));
661 printf(" Unknown (VIC %3u)\n", vic
);
662 fail("Unknown VIC %u.\n", vic
);
665 if (vic
== 1 && !for_ycbcr420
)
667 if (++cta
.vics
[vic
][for_ycbcr420
] == 2)
668 fail("Duplicate %sVIC %u.\n", for_ycbcr420
? "YCbCr 4:2:0 " : "", vic
);
669 if (for_ycbcr420
&& cta
.preparsed_has_vic
[0][vic
])
670 fail("YCbCr 4:2:0-only VIC %u is also a regular VIC.\n", vic
);
672 if (n
> 1 && ascending
&& first_vic_is_1_to_4
&& have_vics_5_and_up
)
673 warn("All VICs are in ascending order, and the first (preferred) VIC <= 4, is that intended?\n");
676 cta_vfd
edid_state::cta_parse_vfd(const unsigned char *x
, unsigned lvfd
)
681 if (cta
.avi_v4_length
< 15)
682 cta
.avi_v4_length
= 15;
683 vfd
.rid
= x
[0] & 0x3f;
684 if (vfd
.rid
>= ARRAY_SIZE(rids
)) {
688 vfd
.bfr50
= !!(x
[0] & 0x80);
689 vfd
.fr24
= !!(x
[0] & 0x40);
690 vfd
.bfr60
= lvfd
> 1 ? !!(x
[1] & 0x80) : 1;
691 vfd
.fr144
= lvfd
> 1 ? !!(x
[1] & 0x40) : 0;
692 vfd
.fr_factor
= lvfd
> 1 ? (x
[1] & 0x3f) : 3;
693 vfd
.fr48
= lvfd
> 2 ? !!(x
[2] & 0x01) : 0;
697 static bool vfd_has_rate(cta_vfd
&vfd
, unsigned rate_index
)
699 static const unsigned factors
[6] = {
702 unsigned rate
= vf_rate_values
[rate_index
];
725 for (unsigned i
= 0; i
< ARRAY_SIZE(factors
); i
++)
726 if (factors
[i
] == factor
&& (vfd
.fr_factor
& (1 << i
)))
731 void edid_state::cta_vfdb(const unsigned char *x
, unsigned n
)
734 fail("Length is 0.\n");
737 unsigned char flags
= *x
++;
738 unsigned lvfd
= (flags
& 3) + 1;
741 fail("Length - 1 is not a multiple of Lvfd (%u).\n", lvfd
);
745 printf(" Supports YCbCr 4:2:0\n");
747 printf(" NTSC fractional frame rates are preferred\n");
748 for (unsigned i
= 0; i
< n
; i
+= lvfd
, x
+= lvfd
) {
749 unsigned char rid
= x
[0] & 0x3f;
750 cta_vfd vfd
= cta_parse_vfd(x
, lvfd
);
752 if (lvfd
> 2 && (x
[2] & 0xfe))
753 fail("Bits F31-F37 must be 0.\n");
754 if (lvfd
> 3 && x
[3])
755 fail("Bits F40-F47 must be 0.\n");
756 if (rid
== 0 || rid
>= ARRAY_SIZE(rids
)) {
757 fail("Unknown RID %u.\n", rid
);
760 for (unsigned rate_index
= 1; rate_index
< ARRAY_SIZE(vf_rate_values
); rate_index
++) {
761 if (!vfd_has_rate(vfd
, rate_index
))
763 struct timings t
= calc_ovt_mode(rids
[vfd
.rid
].hact
,
765 rids
[vfd
.rid
].hratio
,
766 rids
[vfd
.rid
].vratio
,
767 vf_rate_values
[rate_index
]);
769 sprintf(type
, "RID %u@%up", rid
, vf_rate_values
[rate_index
]);
770 print_timings(" ", &t
, type
);
771 if (rid_to_vic(vfd
.rid
, rate_index
))
772 fail("%s not allowed since it maps to VIC %u.\n",
773 type
, rid_to_vic(vfd
.rid
, rate_index
));
778 void edid_state::print_vic_index(const char *prefix
, unsigned idx
, const char *suffix
, bool ycbcr420
)
782 if (idx
< cta
.preparsed_svds
[0].size()) {
783 unsigned char vic
= cta
.preparsed_svds
[0][idx
];
784 const struct timings
*t
= find_vic_id(vic
);
787 sprintf(buf
, "VIC %3u", vic
);
790 struct timings tmp
= *t
;
791 tmp
.ycbcr420
= ycbcr420
;
792 print_timings(prefix
, &tmp
, buf
, suffix
);
794 printf("%sUnknown (%s%s%s)\n", prefix
, buf
,
795 *suffix
? ", " : "", suffix
);
798 // Should not happen!
799 printf("%sSVD Index %u is out of range", prefix
, idx
+ 1);
801 printf(" (%s)", suffix
);
806 void edid_state::cta_y420cmdb(const unsigned char *x
, unsigned length
)
808 unsigned max_idx
= 0;
812 printf(" All VDB SVDs\n");
816 if (memchk(x
, length
)) {
817 printf(" Empty Capability Map\n");
818 fail("Empty Capability Map.\n");
822 for (i
= 0; i
< length
; i
++) {
823 unsigned char v
= x
[i
];
826 for (j
= 0; j
< 8; j
++) {
830 print_vic_index(" ", i
* 8 + j
, "", true);
832 if (max_idx
< cta
.preparsed_svds
[0].size()) {
833 unsigned vic
= cta
.preparsed_svds
[0][max_idx
];
834 if (cta
.preparsed_has_vic
[1][vic
])
835 fail("VIC %u is also a YCbCr 4:2:0-only VIC.\n", vic
);
837 cta
.has_ycbcr420
= true;
840 if (max_idx
>= cta
.preparsed_svds
[0].size())
841 fail("Max index %u > %u (#SVDs).\n",
842 max_idx
+ 1, cta
.preparsed_svds
[0].size());
845 void edid_state::cta_print_svr(unsigned char svr
, vec_timings_ext
&vec_tim
)
849 if ((svr
> 0 && svr
< 128) || (svr
> 192 && svr
< 254)) {
850 const struct timings
*t
;
851 unsigned char vic
= svr
;
853 sprintf(suffix
, "VIC %3u", vic
);
855 t
= find_vic_id(vic
);
857 print_timings(" ", t
, suffix
);
858 vec_tim
.push_back(timings_ext(*t
, suffix
, ""));
860 printf(" %s: Unknown\n", suffix
);
861 fail("Unknown VIC %u.\n", vic
);
864 } else if (svr
>= 129 && svr
<= 144) {
865 sprintf(suffix
, "DTD %3u", svr
- 128);
866 if (svr
>= cta
.preparsed_total_dtds
+ 129) {
867 printf(" %s: Invalid\n", suffix
);
868 fail("Invalid DTD %u.\n", svr
- 128);
870 printf(" %s\n", suffix
);
871 vec_tim
.push_back(timings_ext(svr
, suffix
));
874 } else if (svr
>= 145 && svr
<= 160) {
875 sprintf(suffix
, "VTDB %3u", svr
- 144);
876 if (svr
>= cta
.preparsed_total_vtdbs
+ 145) {
877 printf(" %s: Invalid\n", suffix
);
878 fail("Invalid VTDB %u.\n", svr
- 144);
880 printf(" %s\n", suffix
);
881 vec_tim
.push_back(timings_ext(svr
, suffix
));
884 } else if (svr
>= 161 && svr
<= 175) {
885 sprintf(suffix
, "RID %u@%up",
886 cta
.preparsed_first_vfd
.rid
, vf_rate_values
[svr
- 160]);
887 if (!vfd_has_rate(cta
.preparsed_first_vfd
, svr
- 160)) {
888 printf(" %s: Invalid\n", suffix
);
889 fail("Invalid %s.\n", suffix
);
891 printf(" %s\n", suffix
);
892 vec_tim
.push_back(timings_ext(svr
, suffix
));
895 } else if (svr
== 254) {
896 sprintf(suffix
, "T8VTDB");
897 if (!cta
.preparsed_has_t8vtdb
) {
898 printf(" %s: Invalid\n", suffix
);
899 fail("Invalid T8VTDB.\n");
901 sprintf(suffix
, "DMT 0x%02x", cta
.preparsed_t8vtdb_dmt
);
902 printf(" %s\n", suffix
);
903 vec_tim
.push_back(timings_ext(svr
, suffix
));
909 void edid_state::cta_vfpdb(const unsigned char *x
, unsigned length
)
914 fail("Empty Data Block with length %u.\n", length
);
917 cta
.preferred_timings_vfpdb
.clear();
918 for (i
= 0; i
< length
; i
++)
919 cta_print_svr(x
[i
], cta
.preferred_timings_vfpdb
);
922 void edid_state::cta_nvrdb(const unsigned char *x
, unsigned length
)
925 fail("Empty Data Block with length %u.\n", length
);
929 unsigned char flags
= length
== 1 ? 0 : x
[1];
931 cta
.native_timing_nvrdb
.clear();
932 cta_print_svr(x
[0], cta
.native_timing_nvrdb
);
933 if ((flags
& 1) && length
< 6) {
934 fail("Data Block too short for Image Size (length = %u).\n", length
);
938 fail("Bits F41-F46 must be 0.\n");
942 unsigned w
= (x
[3] << 8) | x
[2];
943 unsigned h
= (x
[5] << 8) | x
[4];
946 fail("Image Size has a zero width and/or height.\n");
949 printf(" Image Size: %ux%u mm\n", w
, h
);
951 printf(" Image Size: %.1fx%.1f mm\n", w
/ 10.0, h
/ 10.0);
954 static std::string
hdmi_latency2s(unsigned char l
, bool is_video
)
959 return is_video
? "Video not supported" : "Audio not supported";
960 return std::to_string(2 * (l
- 1)) + " ms";
963 void edid_state::hdmi_latency(unsigned char vid_lat
, unsigned char aud_lat
,
966 const char *vid
= is_ilaced
? "Interlaced video" : "Video";
967 const char *aud
= is_ilaced
? "Interlaced audio" : "Audio";
969 printf(" %s latency: %s\n", vid
, hdmi_latency2s(vid_lat
, true).c_str());
970 printf(" %s latency: %s\n", aud
, hdmi_latency2s(aud_lat
, false).c_str());
972 if (vid_lat
> 251 && vid_lat
!= 0xff)
973 fail("Invalid %s latency value %u.\n", vid
, vid_lat
);
974 if (aud_lat
> 251 && aud_lat
!= 0xff)
975 fail("Invalid %s latency value %u.\n", aud
, aud_lat
);
977 if (!vid_lat
|| vid_lat
> 251)
979 if (!aud_lat
|| aud_lat
> 251)
982 unsigned vid_ms
= 2 * (vid_lat
- 1);
983 unsigned aud_ms
= 2 * (aud_lat
- 1);
985 // HDMI 2.0 latency checks for devices without HDMI output
987 warn("%s latency < %s latency (%u ms < %u ms). This is discouraged for devices without HDMI output.\n",
988 aud
, vid
, aud_ms
, vid_ms
);
989 else if (vid_ms
+ 20 < aud_ms
)
990 warn("%s latency + 20 < %s latency (%u + 20 ms < %u ms). This is forbidden for devices without HDMI output.\n",
991 vid
, aud
, vid_ms
, aud_ms
);
992 else if (vid_ms
< aud_ms
)
993 warn("%s latency < %s latency (%u ms < %u ms). This is discouraged for devices without HDMI output.\n",
994 vid
, aud
, vid_ms
, aud_ms
);
997 void edid_state::cta_hdmi_block(const unsigned char *x
, unsigned length
)
999 unsigned len_vic
, len_3d
;
1002 fail("Empty Data Block with length %u.\n", length
);
1005 printf(" Source physical address: %x.%x.%x.%x\n", x
[0] >> 4, x
[0] & 0x0f,
1006 x
[1] >> 4, x
[1] & 0x0f);
1012 printf(" Supports_AI\n");
1014 printf(" DC_48bit\n");
1016 printf(" DC_36bit\n");
1018 printf(" DC_30bit\n");
1020 printf(" DC_Y444\n");
1021 /* two reserved bits */
1023 printf(" DVI_Dual\n");
1028 unsigned rate
= x
[3] * 5;
1029 printf(" Maximum TMDS clock: %u MHz\n", rate
);
1030 cta
.hdmi_max_rate
= rate
;
1032 fail("HDMI VSDB Max TMDS rate is > 340.\n");
1038 printf(" Supported Content Types:\n");
1040 printf(" Graphics\n");
1044 printf(" Cinema\n");
1051 hdmi_latency(x
[b
], x
[b
+ 1], false);
1054 if (x
[b
] == x
[b
+ 2] &&
1055 x
[b
+ 1] == x
[b
+ 3])
1056 warn("Progressive and Interlaced latency values are identical, no need for both.\n");
1058 hdmi_latency(x
[b
], x
[b
+ 1], true);
1067 bool formats
= false;
1069 printf(" Extended HDMI video details:\n");
1071 printf(" 3D present\n");
1072 if ((x
[b
] & 0x60) == 0x20) {
1073 printf(" All advertised VICs are 3D-capable\n");
1076 if ((x
[b
] & 0x60) == 0x40) {
1077 printf(" 3D-capable-VIC mask present\n");
1081 switch (x
[b
] & 0x18) {
1084 printf(" Base EDID image size is aspect ratio\n");
1087 printf(" Base EDID image size is in units of 1 cm\n");
1090 printf(" Base EDID image size is in units of 5 cm\n");
1091 base
.max_display_width_mm
*= 5;
1092 base
.max_display_height_mm
*= 5;
1093 printf(" Recalculated image size: %u cm x %u cm\n",
1094 base
.max_display_width_mm
/ 10, base
.max_display_height_mm
/ 10);
1098 len_vic
= (x
[b
] & 0xe0) >> 5;
1099 len_3d
= (x
[b
] & 0x1f) >> 0;
1105 printf(" HDMI VICs:\n");
1106 for (i
= 0; i
< len_vic
; i
++) {
1107 unsigned char vic
= x
[b
+ i
];
1108 const struct timings
*t
;
1110 if (vic
&& vic
<= ARRAY_SIZE(edid_hdmi_mode_map
)) {
1111 std::string suffix
= "HDMI VIC " + std::to_string(vic
);
1112 cta
.supported_hdmi_vic_codes
|= 1 << (vic
- 1);
1113 t
= find_vic_id(edid_hdmi_mode_map
[vic
- 1]);
1114 print_timings(" ", t
, suffix
.c_str());
1116 printf(" Unknown (HDMI VIC %u)\n", vic
);
1117 fail("Unknown HDMI VIC %u.\n", vic
);
1128 /* 3D_Structure_ALL_15..8 */
1130 printf(" 3D: Side-by-side (half, quincunx)\n");
1132 printf(" 3D: Side-by-side (half, horizontal)\n");
1133 /* 3D_Structure_ALL_7..0 */
1136 printf(" 3D: Top-and-bottom\n");
1138 printf(" 3D: L + depth + gfx + gfx-depth\n");
1140 printf(" 3D: L + depth\n");
1142 printf(" 3D: Side-by-side (full)\n");
1144 printf(" 3D: Line-alternative\n");
1146 printf(" 3D: Field-alternative\n");
1148 printf(" 3D: Frame-packing\n");
1157 printf(" 3D VIC indices that support these capabilities:\n");
1158 /* worst bit ordering ever */
1159 for (i
= 0; i
< 8; i
++)
1160 if (x
[b
+ 1] & (1 << i
)) {
1161 print_vic_index(" ", i
, "");
1164 for (i
= 0; i
< 8; i
++)
1165 if (x
[b
] & (1 << i
)) {
1166 print_vic_index(" ", i
+ 8, "");
1171 if (max_idx
>= (int)cta
.preparsed_svds
[0].size())
1172 fail("HDMI 3D VIC indices max index %d > %u (#SVDs).\n",
1173 max_idx
+ 1, cta
.preparsed_svds
[0].size());
1180 * (optionally: 3D_Detail_X and reserved)
1185 unsigned end
= b
+ len_3d
;
1188 printf(" 3D VIC indices with specific capabilities:\n");
1190 unsigned char idx
= x
[b
] >> 4;
1195 switch (x
[b
] & 0x0f) {
1196 case 0: s
= "frame packing"; break;
1197 case 1: s
= "field alternative"; break;
1198 case 2: s
= "line alternative"; break;
1199 case 3: s
= "side-by-side (full)"; break;
1200 case 4: s
= "L + depth"; break;
1201 case 5: s
= "L + depth + gfx + gfx-depth"; break;
1202 case 6: s
= "top-and-bottom"; break;
1205 switch (x
[b
+ 1] >> 4) {
1206 case 0x00: s
+= ", any subsampling"; break;
1207 case 0x01: s
+= ", horizontal"; break;
1208 case 0x02: case 0x03: case 0x04: case 0x05:
1209 s
+= ", not in use";
1210 fail("not-in-use 3D_Detail_X value 0x%02x.\n",
1213 case 0x06: s
+= ", all quincunx combinations"; break;
1214 case 0x07: s
+= ", quincunx odd/left, odd/right"; break;
1215 case 0x08: s
+= ", quincunx odd/left, even/right"; break;
1216 case 0x09: s
+= ", quincunx even/left, odd/right"; break;
1217 case 0x0a: s
+= ", quincunx even/left, even/right"; break;
1220 fail("reserved 3D_Detail_X value 0x%02x.\n",
1227 s
+= utohex(x
[b
] & 0x0f) + ")";
1228 fail("Unknown 3D_Structure_X value 0x%02x.\n", x
[b
] & 0x0f);
1231 print_vic_index(" ", idx
, s
.c_str());
1232 if ((x
[b
] & 0x0f) >= 8)
1236 if (max_idx
>= (int)cta
.preparsed_svds
[0].size())
1237 fail("HDMI 2D VIC indices max index %d > %u (#SVDs).\n",
1238 max_idx
+ 1, cta
.preparsed_svds
[0].size());
1241 static const char *max_frl_rates
[] = {
1243 "3 Gbps per lane on 3 lanes",
1244 "3 and 6 Gbps per lane on 3 lanes",
1245 "3 and 6 Gbps per lane on 3 lanes, 6 Gbps on 4 lanes",
1246 "3 and 6 Gbps per lane on 3 lanes, 6 and 8 Gbps on 4 lanes",
1247 "3 and 6 Gbps per lane on 3 lanes, 6, 8 and 10 Gbps on 4 lanes",
1248 "3 and 6 Gbps per lane on 3 lanes, 6, 8, 10 and 12 Gbps on 4 lanes",
1251 static const char *dsc_max_slices
[] = {
1253 "up to 1 slice and up to (340 MHz/Ksliceadjust) pixel clock per slice",
1254 "up to 2 slices and up to (340 MHz/Ksliceadjust) pixel clock per slice",
1255 "up to 4 slices and up to (340 MHz/Ksliceadjust) pixel clock per slice",
1256 "up to 8 slices and up to (340 MHz/Ksliceadjust) pixel clock per slice",
1257 "up to 8 slices and up to (400 MHz/Ksliceadjust) pixel clock per slice",
1258 "up to 12 slices and up to (400 MHz/Ksliceadjust) pixel clock per slice",
1259 "up to 12 slices and up to (600 MHz/Ksliceadjust) pixel clock per slice",
1262 static void cta_hf_eeodb(const unsigned char *x
, unsigned length
)
1264 printf(" EDID Extension Block Count: %u\n", x
[0]);
1266 fail("Block is too long.\n");
1268 fail("Extension Block Count == %u.\n", x
[0]);
1271 void edid_state::cta_hf_scdb(const unsigned char *x
, unsigned length
)
1273 unsigned rate
= x
[1] * 5;
1276 printf(" Version: %u\n", x
[0]);
1278 printf(" Maximum TMDS Character Rate: %u MHz\n", rate
);
1279 if (rate
<= 340 || rate
> 600)
1280 fail("Max TMDS rate is > 0 and <= 340 or > 600.\n");
1281 if (rate
< cta
.hdmi_max_rate
)
1282 fail("HDMI Forum VSDB rate < HDMI VSDB rate.\n");
1284 cta
.hdmi_max_rate
= rate
;
1287 printf(" SCDC Present\n");
1289 printf(" SCDC Read Request Capable\n");
1291 printf(" Supports Cable Status\n");
1293 printf(" Supports Color Content Bits Per Component Indication\n");
1295 printf(" Supports scrambling for <= 340 Mcsc\n");
1297 printf(" Supports 3D Independent View signaling\n");
1299 printf(" Supports 3D Dual View signaling\n");
1301 printf(" Supports 3D OSD Disparity signaling\n");
1303 unsigned max_frl_rate
= x
[3] >> 4;
1305 printf(" Max Fixed Rate Link: ");
1306 if (max_frl_rate
< ARRAY_SIZE(max_frl_rates
)) {
1307 printf("%s\n", max_frl_rates
[max_frl_rate
]);
1309 printf("Unknown (0x%02x)\n", max_frl_rate
);
1310 fail("Unknown Max Fixed Rate Link (0x%02x).\n", max_frl_rate
);
1312 if (max_frl_rate
== 1 && rate
< 300)
1313 fail("Max Fixed Rate Link is 1, but Max TMDS rate < 300.\n");
1314 else if (max_frl_rate
>= 2 && rate
< 600)
1315 fail("Max Fixed Rate Link is >= 2, but Max TMDS rate < 600.\n");
1318 // Currently I do not really know how to translate the
1319 // Max FRL value to an equivalent max clock frequency.
1320 // So reset this field to 0 to skip any clock rate checks.
1321 cta
.hdmi_max_rate
= 0;
1324 printf(" Supports UHD VIC\n");
1326 printf(" Supports 16-bits/component Deep Color 4:2:0 Pixel Encoding\n");
1328 printf(" Supports 12-bits/component Deep Color 4:2:0 Pixel Encoding\n");
1330 printf(" Supports 10-bits/component Deep Color 4:2:0 Pixel Encoding\n");
1336 printf(" Supports FAPA End Extended\n");
1338 printf(" Supports QMS\n");
1340 printf(" Supports Mdelta\n");
1342 printf(" Supports media rates below VRRmin (CinemaVRR, deprecated)\n");
1343 warn("CinemaVRR is deprecated and must be cleared.\n");
1346 printf(" Supports negative Mvrr values\n");
1348 printf(" Supports Fast Vactive\n");
1350 printf(" Supports Auto Low-Latency Mode\n");
1352 printf(" Supports a FAPA in blanking after first active video line\n");
1359 printf(" VRRmin: %u Hz\n", v
);
1361 fail("VRRmin > 48.\n");
1363 v
= (x
[5] & 0xc0) << 2 | x
[6];
1365 printf(" VRRmax: %u Hz\n", v
);
1367 fail("VRRmin == 0, but VRRmax isn't.\n");
1369 fail("VRRmax < 100.\n");
1376 printf(" Supports VESA DSC 1.2a compression\n");
1378 printf(" Supports Compressed Video Transport for 4:2:0 Pixel Encoding\n");
1380 printf(" Supports QMS TFRmax\n");
1382 printf(" Supports QMS TFRmin\n");
1384 printf(" Supports Compressed Video Transport at any valid 1/16th bit bpp\n");
1386 printf(" Supports 16 bpc Compressed Video Transport\n");
1388 printf(" Supports 12 bpc Compressed Video Transport\n");
1390 printf(" Supports 10 bpc Compressed Video Transport\n");
1392 unsigned max_slices
= x
[8] & 0xf;
1394 printf(" DSC Max Slices: ");
1395 if (max_slices
< ARRAY_SIZE(dsc_max_slices
)) {
1396 printf("%s\n", dsc_max_slices
[max_slices
]);
1398 printf("Unknown (%u), interpreted as: %s\n", max_slices
,
1400 warn("Unknown DSC Max Slices (%u).\n", max_slices
);
1404 unsigned max_frl_rate
= x
[8] >> 4;
1406 printf(" DSC Max Fixed Rate Link: ");
1407 if (max_frl_rate
< ARRAY_SIZE(max_frl_rates
)) {
1408 printf("%s\n", max_frl_rates
[max_frl_rate
]);
1410 printf("Unknown (0x%02x)\n", max_frl_rate
);
1411 fail("Unknown DSC Max Fixed Rate Link (0x%02x).\n", max_frl_rate
);
1415 printf(" Maximum number of bytes in a line of chunks: %u\n",
1416 1024 * (1 + (x
[9] & 0x3f)));
1419 // Convert a PQ value (0-1) to cd/m^2 aka nits (0-10000)
1420 static double pq2nits(double pq
)
1422 const double m1
= 2610.0 / 16384.0;
1423 const double m2
= 128.0 * (2523.0 / 4096.0);
1424 const double c1
= 3424.0 / 4096.0;
1425 const double c2
= 32.0 * (2413.0 / 4096.0);
1426 const double c3
= 32.0 * (2392.0 / 4096.0);
1427 double e
= pow(pq
, 1.0 / m2
);
1433 v
= pow(v
, 1.0 / m1
);
1437 static double perc2d(unsigned char x
)
1442 return 100.0 * (m
/ 64.0) * pow(10, -e
);
1445 static void cta_hf_sbtmdb(const unsigned char *x
, unsigned length
)
1450 fail("Block is too short.\n");
1451 printf(" Version: %d\n", x
[0] & 0xf);
1452 switch ((x
[0] >> 5) & 3) {
1454 printf(" Does not support a General RDM format\n");
1457 printf(" Supports an SDR-range General RDM format\n");
1460 printf(" Supports an HDR-range General RDM format\n");
1463 fail("Invalid GRDM Support value.\n");
1469 bool uses_hgig_drdm
= true;
1471 printf(" Supports a D-RDM format\n");
1473 printf(" Use HGIG D-RDM\n");
1476 printf(" HGIG D-RDM is not used\n");
1477 uses_hgig_drdm
= false;
1480 printf(" PBnits[0] = 600 cd/m^2\n");
1483 printf(" PBnits[0] = 1000 cd/m^2\n");
1486 printf(" PBnits[0] = 4000 cd/m^2\n");
1489 printf(" PBnits[0] = 10000 cd/m^2\n");
1492 fail("Invalid HGIG D-DRM value.\n");
1496 bool has_chromaticities
= false;
1499 printf(" MaxRGB\n");
1500 switch (x
[1] >> 6) {
1502 printf(" Gamut is explicit\n");
1503 has_chromaticities
= true;
1506 printf(" Gamut is Rec. ITU-R BT.709\n");
1509 printf(" Gamut is SMPTE ST 2113\n");
1512 printf(" Gamut is Rec. ITU-R BT.2020\n");
1517 if (has_chromaticities
) {
1518 printf(" Red: (%.5f, %.5f)\n", chrom2d(x
), chrom2d(x
+ 2));
1519 printf(" Green: (%.5f, %.5f)\n", chrom2d(x
+ 4), chrom2d(x
+ 6));
1520 printf(" Blue: (%.5f, %.5f)\n", chrom2d(x
+ 8), chrom2d(x
+ 10));
1521 printf(" White: (%.5f, %.5f)\n", chrom2d(x
+ 12), chrom2d(x
+ 14));
1527 printf(" Min Brightness 10: %.8f cd/m^2\n", pq2nits((x
[0] << 1) / 4095.0));
1528 printf(" Peak Brightness 100: %u cd/m^2\n", (unsigned)pq2nits((x
[1] << 4) / 4095.0));
1533 printf(" Percentage of Peak Brightness P0: %.2f%%\n", perc2d(x
[0]));
1534 printf(" Peak Brightness P0: %.8f cd/m^2\n", pq2nits((x
[1] << 1) / 4095.0));
1539 printf(" Percentage of Peak Brightness P1: %.2f%%\n", perc2d(x
[0]));
1540 printf(" Peak Brightness P1: %.8f cd/m^2\n", pq2nits((x
[1] << 1) / 4095.0));
1545 printf(" Percentage of Peak Brightness P2: %.2f%%\n", perc2d(x
[0]));
1546 printf(" Peak Brightness P2: %.8f cd/m^2\n", pq2nits((x
[1] << 1) / 4095.0));
1551 printf(" Percentage of Peak Brightness P3: %.2f%%\n", perc2d(x
[0]));
1552 printf(" Peak Brightness P3: %.8f cd/m^2\n", pq2nits((x
[1] << 1) / 4095.0));
1555 static void cta_amd(const unsigned char *x
, unsigned length
)
1557 // These Freesync values are reversed engineered by looking
1558 // at existing EDIDs.
1559 printf(" Version: %u\n", x
[0]);
1562 // https://github.com/torvalds/linux/commit/ec8e59cb4e0c1a52d5a541fff9dcec398b48f7b4
1563 printf(" Feature Caps: 0x%02x\n", x
[1]);
1565 printf(" Replay Supported\n");
1567 printf(" Minimum Refresh Rate: %u Hz\n", x
[2]);
1568 printf(" Maximum Refresh Rate: %u Hz\n", x
[3]);
1569 // Freesync 1.x flags
1570 // One or more of the 0xe6 bits signal that the VESA MCCS
1571 // protocol is used to switch the Freesync range
1572 printf(" Flags 1.x: 0x%02x%s\n", x
[4],
1573 (x
[4] & 0xe6) ? " (MCCS)" : "");
1575 // Freesync 2.x flags
1576 // Bit 2 no doubt indicates if the monitor supports Local Dimming
1577 // There are probably also bits to signal support of the
1578 // FreeSync2_scRGB and FreeSync2_Gamma22 HDR display modes.
1579 // I suspect bits 0 and 1.
1580 printf(" Flags 2.x: 0x%02x\n", x
[5]);
1581 // The AMD tone mapping tutorial referred to in the URL below
1582 // mentions that the Freesync HDR info reports max/min
1583 // luminance of the monitor with and without local dimming.
1585 // https://gpuopen.com/learn/using-amd-freesync-premium-pro-hdr-code-samples/
1587 // So I assume that the first two luminance values are
1588 // the max/min luminance of the display and the next two
1589 // luminance values are the max/min luminance values when
1590 // local dimming is disabled. The values I get seem to
1592 printf(" Maximum luminance: %u (%.3f cd/m^2)\n",
1593 x
[6], 50.0 * pow(2, x
[6] / 32.0));
1594 printf(" Minimum luminance: %u (%.3f cd/m^2)\n",
1595 x
[7], (50.0 * pow(2, x
[6] / 32.0)) * pow(x
[7] / 255.0, 2) / 100.0);
1597 // One or both bytes can be 0. The meaning of that
1599 printf(" Maximum luminance (without local dimming): %u (%.3f cd/m^2)\n",
1600 x
[8], 50.0 * pow(2, x
[8] / 32.0));
1601 printf(" Minimum luminance (without local dimming): %u (%.3f cd/m^2)\n",
1602 x
[9], (50.0 * pow(2, x
[8] / 32.0)) * pow(x
[9] / 255.0, 2) / 100.0);
1604 // These bytes are always 0x08 0x2f. If these values
1605 // represent max/min luminance as well, then these
1606 // would map to 59.460 and 0.020 cd/m^2 respectively.
1607 // I wonder if this somehow relates to SDR.
1608 printf(" Unknown: 0x%02x 0x%02x\n", x
[8], x
[9]);
1613 static std::string
display_use_case(unsigned char x
)
1616 case 1: return "Test equipment";
1617 case 2: return "Generic display";
1618 case 3: return "Television display";
1619 case 4: return "Desktop productivity display";
1620 case 5: return "Desktop gaming display";
1621 case 6: return "Presentation display";
1622 case 7: return "Virtual reality headset";
1623 case 8: return "Augmented reality";
1624 case 16: return "Video wall display";
1625 case 17: return "Medical imaging display";
1626 case 18: return "Dedicated gaming display";
1627 case 19: return "Dedicated video monitor display";
1628 case 20: return "Accessory display";
1631 fail("Unknown Display product primary use case 0x%02x.\n", x
);
1635 static void cta_microsoft(const unsigned char *x
, unsigned length
)
1637 // This VSDB is documented at:
1638 // https://docs.microsoft.com/en-us/windows-hardware/drivers/display/specialized-monitors-edid-extension
1639 printf(" Version: %u\n", x
[0]);
1641 // In version 1 and 2 these bits should always be set to 0.
1642 printf(" Desktop Usage: %u\n", (x
[1] >> 6) & 1);
1643 printf(" Third-Party Usage: %u\n", (x
[1] >> 5) & 1);
1645 printf(" Display Product Primary Use Case: %s\n",
1646 display_use_case(x
[1] & 0x1f).c_str());
1647 printf(" Container ID: %s\n", containerid2s(x
+ 2).c_str());
1650 static void cta_hdr10plus(const unsigned char *x
, unsigned length
)
1653 fail("Empty Data Block with length %u.\n", length
);
1656 printf(" Application Version: %u\n", x
[0] & 3);
1657 printf(" Full Frame Peak Luminance Index: %u\n", (x
[0] >> 2) & 3);
1658 printf(" Peak Luminance Index: %u\n", x
[0] >> 4);
1659 hex_block(" ", x
+ 1, length
- 1);
1662 static void cta_dolby_video(const unsigned char *x
, unsigned length
)
1664 unsigned char version
= (x
[0] >> 5) & 0x07;
1666 printf(" Version: %u (%u bytes)\n", version
, length
+ 5);
1668 printf(" Supports YUV422 12 bit\n");
1672 printf(" Supports 2160p60\n");
1674 printf(" Supports global dimming\n");
1675 unsigned char dm_version
= x
[16];
1676 printf(" DM Version: %u.%u\n", dm_version
>> 4, dm_version
& 0xf);
1677 unsigned pq
= (x
[14] << 4) | (x
[13] >> 4);
1678 printf(" Target Min PQ: %u (%.8f cd/m^2)\n", pq
, pq2nits(pq
/ 4095.0));
1679 pq
= (x
[15] << 4) | (x
[13] & 0xf);
1680 printf(" Target Max PQ: %u (%u cd/m^2)\n", pq
, (unsigned)pq2nits(pq
/ 4095.0));
1681 printf(" Rx, Ry: %.8f, %.8f\n",
1682 ((x
[1] >> 4) | (x
[2] << 4)) / 4096.0,
1683 ((x
[1] & 0xf) | (x
[3] << 4)) / 4096.0);
1684 printf(" Gx, Gy: %.8f, %.8f\n",
1685 ((x
[4] >> 4) | (x
[5] << 4)) / 4096.0,
1686 ((x
[4] & 0xf) | (x
[6] << 4)) / 4096.0);
1687 printf(" Bx, By: %.8f, %.8f\n",
1688 ((x
[7] >> 4) | (x
[8] << 4)) / 4096.0,
1689 ((x
[7] & 0xf) | (x
[9] << 4)) / 4096.0);
1690 printf(" Wx, Wy: %.8f, %.8f\n",
1691 ((x
[10] >> 4) | (x
[11] << 4)) / 4096.0,
1692 ((x
[10] & 0xf) | (x
[12] << 4)) / 4096.0);
1698 printf(" Supports 2160p60\n");
1700 printf(" Supports global dimming\n");
1701 unsigned char dm_version
= (x
[0] >> 2) & 0x07;
1702 printf(" DM Version: %u.x\n", dm_version
+ 2);
1703 printf(" Colorimetry: %s\n", (x
[2] & 0x01) ? "P3-D65" : "ITU-R BT.709");
1704 printf(" Low Latency: %s\n", (x
[3] & 0x01) ? "Standard + Low Latency" : "Only Standard");
1705 double lm
= (x
[2] >> 1) / 127.0;
1706 printf(" Target Min Luminance: %.8f cd/m^2\n", lm
* lm
);
1707 printf(" Target Max Luminance: %u cd/m^2\n", 100 + (x
[1] >> 1) * 50);
1709 printf(" Rx, Ry: %.8f, %.8f\n", x
[4] / 256.0, x
[5] / 256.0);
1710 printf(" Gx, Gy: %.8f, %.8f\n", x
[6] / 256.0, x
[7] / 256.0);
1711 printf(" Bx, By: %.8f, %.8f\n", x
[8] / 256.0, x
[9] / 256.0);
1713 double xmin
= 0.625;
1714 double xstep
= (0.74609375 - xmin
) / 31.0;
1716 double ystep
= (0.37109375 - ymin
) / 31.0;
1718 printf(" Unique Rx, Ry: %.8f, %.8f\n",
1719 xmin
+ xstep
* (x
[6] >> 3),
1720 ymin
+ ystep
* (((x
[6] & 0x7) << 2) | (x
[4] & 0x01) | ((x
[5] & 0x01) << 1)));
1721 xstep
= 0.49609375 / 127.0;
1723 ystep
= (0.99609375 - ymin
) / 127.0;
1724 printf(" Unique Gx, Gy: %.8f, %.8f\n",
1725 xstep
* (x
[4] >> 1), ymin
+ ystep
* (x
[5] >> 1));
1727 xstep
= (0.15234375 - xmin
) / 7.0;
1729 ystep
= (0.05859375 - ymin
) / 7.0;
1730 printf(" Unique Bx, By: %.8f, %.8f\n",
1731 xmin
+ xstep
* (x
[3] >> 5),
1732 ymin
+ ystep
* ((x
[3] >> 2) & 0x07));
1739 printf(" Supports Backlight Control\n");
1741 printf(" Supports global dimming\n");
1742 unsigned char dm_version
= (x
[0] >> 2) & 0x07;
1743 printf(" DM Version: %u.x\n", dm_version
+ 2);
1744 printf(" Backlt Min Luma: %u cd/m^2\n", 25 + (x
[1] & 0x03) * 25);
1745 printf(" Interface: ");
1746 switch (x
[2] & 0x03) {
1747 case 0: printf("Low-Latency\n"); break;
1748 case 1: printf("Low-Latency + Low-Latency-HDMI\n"); break;
1749 case 2: printf("Standard + Low-Latency\n"); break;
1750 case 3: printf("Standard + Low-Latency + Low-Latency-HDMI\n"); break;
1752 printf(" Supports 10b 12b 444: ");
1753 switch ((x
[3] & 0x01) << 1 | (x
[4] & 0x01)) {
1754 case 0: printf("Not supported\n"); break;
1755 case 1: printf("10 bit\n"); break;
1756 case 2: printf("12 bit\n"); break;
1757 case 3: printf("Reserved\n"); break;
1760 unsigned pq
= 20 * (x
[1] >> 3);
1761 printf(" Target Min PQ v2: %u (%.8f cd/m^2)\n", pq
, pq2nits(pq
/ 4095.0));
1762 pq
= 2055 + 65 * (x
[2] >> 3);
1763 printf(" Target Max PQ v2: %u (%u cd/m^2)\n", pq
, (unsigned)pq2nits(pq
/ 4095.0));
1765 printf(" Unique Rx, Ry: %.8f, %.8f\n",
1766 0.625 + (x
[5] >> 3) / 256.0,
1767 0.25 + (x
[6] >> 3) / 256.0);
1768 printf(" Unique Gx, Gy: %.8f, %.8f\n",
1769 (x
[3] >> 1) / 256.0,
1770 0.5 + (x
[4] >> 1) / 256.0);
1771 printf(" Unique Bx, By: %.8f, %.8f\n",
1772 0.125 + (x
[5] & 0x07) / 256.0,
1773 0.03125 + (x
[6] & 0x07) / 256.0);
1777 static void cta_dolby_audio(const unsigned char *x
, unsigned length
)
1779 unsigned char version
= 1 + (x
[0] & 0x07);
1781 printf(" Version: %u (%u bytes)\n", version
, length
+ 5);
1783 printf(" Headphone playback only\n");
1785 printf(" Height speaker zone present\n");
1787 printf(" Surround speaker zone present\n");
1789 printf(" Center speaker zone present\n");
1791 printf(" Supports Dolby MAT PCM decoding at 48 kHz only, does not support TrueHD\n");
1794 static void cta_uhda_fmm(const unsigned char *x
, unsigned length
)
1796 printf(" Filmmaker Mode Content Type: %u\n", x
[0]);
1797 printf(" Filmmaker Mode Content Subtype: %u\n", x
[1]);
1800 const char *cta_speaker_map
[] = {
1801 "FL/FR - Front Left/Right",
1802 "LFE1 - Low Frequency Effects 1",
1803 "FC - Front Center",
1804 "BL/BR - Back Left/Right",
1806 "FLc/FRc - Front Left/Right of Center",
1807 "RLC/RRC - Rear Left/Right of Center (Deprecated)",
1808 "FLw/FRw - Front Left/Right Wide",
1810 "TpFL/TpFR - Top Front Left/Right",
1812 "TpFC - Top Front Center",
1813 "LS/RS - Left/Right Surround",
1814 "LFE2 - Low Frequency Effects 2",
1815 "TpBC - Top Back Center",
1816 "SiL/SiR - Side Left/Right",
1817 "TpSiL/TpSiR - Top Side Left/Right",
1819 "TpBL/TpBR - Top Back Left/Right",
1820 "BtFC - Bottom Front Center",
1821 "BtFL/BtFR - Bottom Front Left/Right",
1822 "TpLS/TpRS - Top Left/Right Surround (Deprecated for CTA-861)",
1823 "LSd/RSd - Left/Right Surround Direct (HDMI only)",
1827 static void cta_sadb(const unsigned char *x
, unsigned length
)
1829 unsigned sad_deprecated
= 0x7f000;
1834 fail("Empty Data Block with length %u.\n", length
);
1838 sad
= ((x
[2] << 16) | (x
[1] << 8) | x
[0]);
1840 for (i
= 0; cta_speaker_map
[i
]; i
++) {
1841 bool deprecated
= sad_deprecated
& (1 << i
);
1844 printf(" %s%s\n", cta_speaker_map
[i
],
1845 deprecated
? " (Deprecated, use the RCDB)" : "");
1848 warn("Specifies deprecated speakers.\n");
1851 static void cta_vesa_dtcdb(const unsigned char *x
, unsigned length
)
1853 if (length
!= 7 && length
!= 15 && length
!= 31) {
1854 fail("Invalid length %u.\n", length
);
1858 switch (x
[0] >> 6) {
1859 case 0: printf(" White"); break;
1860 case 1: printf(" Red"); break;
1861 case 2: printf(" Green"); break;
1862 case 3: printf(" Blue"); break;
1864 unsigned v
= x
[0] & 0x3f;
1865 printf(" transfer characteristics: %u", v
);
1866 for (unsigned i
= 1; i
< length
; i
++)
1867 printf(" %u", v
+= x
[i
]);
1871 static void cta_vesa_vdddb(const unsigned char *x
, unsigned length
)
1874 fail("Invalid length %u.\n", length
);
1878 printf(" Interface Type: ");
1879 unsigned char v
= x
[0];
1881 case 0: printf("Analog (");
1883 case 0: printf("15HD/VGA"); break;
1884 case 1: printf("VESA NAVI-V (15HD)"); break;
1885 case 2: printf("VESA NAVI-D"); break;
1886 default: printf("Reserved"); break;
1890 case 1: printf("LVDS %u lanes", v
& 0xf); break;
1891 case 2: printf("RSDS %u lanes", v
& 0xf); break;
1892 case 3: printf("DVI-D %u channels", v
& 0xf); break;
1893 case 4: printf("DVI-I analog"); break;
1894 case 5: printf("DVI-I digital %u channels", v
& 0xf); break;
1895 case 6: printf("HDMI-A"); break;
1896 case 7: printf("HDMI-B"); break;
1897 case 8: printf("MDDI %u channels", v
& 0xf); break;
1898 case 9: printf("DisplayPort %u channels", v
& 0xf); break;
1899 case 10: printf("IEEE-1394"); break;
1900 case 11: printf("M1 analog"); break;
1901 case 12: printf("M1 digital %u channels", v
& 0xf); break;
1902 default: printf("Reserved"); break;
1906 printf(" Interface Standard Version: %u.%u\n", x
[1] >> 4, x
[1] & 0xf);
1907 printf(" Content Protection Support: ");
1909 case 0: printf("None\n"); break;
1910 case 1: printf("HDCP\n"); break;
1911 case 2: printf("DTCP\n"); break;
1912 case 3: printf("DPCP\n"); break;
1913 default: printf("Reserved\n"); break;
1916 printf(" Minimum Clock Frequency: %u MHz\n", x
[3] >> 2);
1917 printf(" Maximum Clock Frequency: %u MHz\n", ((x
[3] & 0x03) << 8) | x
[4]);
1918 printf(" Device Native Pixel Format: %ux%u\n",
1919 x
[5] | (x
[6] << 8), x
[7] | (x
[8] << 8));
1920 printf(" Aspect Ratio: %.2f\n", (100 + x
[9]) / 100.0);
1922 printf(" Default Orientation: ");
1923 switch ((v
& 0xc0) >> 6) {
1924 case 0x00: printf("Landscape\n"); break;
1925 case 0x01: printf("Portrait\n"); break;
1926 case 0x02: printf("Not Fixed\n"); break;
1927 case 0x03: printf("Undefined\n"); break;
1929 printf(" Rotation Capability: ");
1930 switch ((v
& 0x30) >> 4) {
1931 case 0x00: printf("None\n"); break;
1932 case 0x01: printf("Can rotate 90 degrees clockwise\n"); break;
1933 case 0x02: printf("Can rotate 90 degrees counterclockwise\n"); break;
1934 case 0x03: printf("Can rotate 90 degrees in either direction)\n"); break;
1936 printf(" Zero Pixel Location: ");
1937 switch ((v
& 0x0c) >> 2) {
1938 case 0x00: printf("Upper Left\n"); break;
1939 case 0x01: printf("Upper Right\n"); break;
1940 case 0x02: printf("Lower Left\n"); break;
1941 case 0x03: printf("Lower Right\n"); break;
1943 printf(" Scan Direction: ");
1945 case 0x00: printf("Not defined\n"); break;
1946 case 0x01: printf("Fast Scan is on the Major (Long) Axis and Slow Scan is on the Minor Axis\n"); break;
1947 case 0x02: printf("Fast Scan is on the Minor (Short) Axis and Slow Scan is on the Major Axis\n"); break;
1948 case 0x03: printf("Reserved\n");
1949 fail("Scan Direction used the reserved value 0x03.\n");
1952 printf(" Subpixel Information: ");
1954 case 0x00: printf("Not defined\n"); break;
1955 case 0x01: printf("RGB vertical stripes\n"); break;
1956 case 0x02: printf("RGB horizontal stripes\n"); break;
1957 case 0x03: printf("Vertical stripes using primary order\n"); break;
1958 case 0x04: printf("Horizontal stripes using primary order\n"); break;
1959 case 0x05: printf("Quad sub-pixels, red at top left\n"); break;
1960 case 0x06: printf("Quad sub-pixels, red at bottom left\n"); break;
1961 case 0x07: printf("Delta (triad) RGB sub-pixels\n"); break;
1962 case 0x08: printf("Mosaic\n"); break;
1963 case 0x09: printf("Quad sub-pixels, RGB + 1 additional color\n"); break;
1964 case 0x0a: printf("Five sub-pixels, RGB + 2 additional colors\n"); break;
1965 case 0x0b: printf("Six sub-pixels, RGB + 3 additional colors\n"); break;
1966 case 0x0c: printf("Clairvoyante, Inc. PenTile Matrix (tm) layout\n"); break;
1967 default: printf("Reserved\n"); break;
1969 printf(" Horizontal and vertical dot/pixel pitch: %.2f x %.2f mm\n",
1970 (double)(x
[0x0c]) / 100.0, (double)(x
[0x0d]) / 100.0);
1972 printf(" Dithering: ");
1974 case 0: printf("None\n"); break;
1975 case 1: printf("Spatial\n"); break;
1976 case 2: printf("Temporal\n"); break;
1977 case 3: printf("Spatial and Temporal\n"); break;
1979 printf(" Direct Drive: %s\n", (v
& 0x20) ? "Yes" : "No");
1980 printf(" Overdrive %srecommended\n", (v
& 0x10) ? "not " : "");
1981 printf(" Deinterlacing: %s\n", (v
& 0x08) ? "Yes" : "No");
1984 printf(" Audio Support: %s\n", (v
& 0x80) ? "Yes" : "No");
1985 printf(" Separate Audio Inputs Provided: %s\n", (v
& 0x40) ? "Yes" : "No");
1986 printf(" Audio Input Override: %s\n", (v
& 0x20) ? "Yes" : "No");
1989 printf(" Audio Delay: %s%u ms\n", (v
& 0x80) ? "" : "-", (v
& 0x7f) * 2);
1991 printf(" Audio Delay: no information provided\n");
1993 printf(" Frame Rate/Mode Conversion: ");
1995 case 0: printf("None\n"); break;
1996 case 1: printf("Single Buffering\n"); break;
1997 case 2: printf("Double Buffering\n"); break;
1998 case 3: printf("Advanced Frame Rate Conversion\n"); break;
2001 printf(" Frame Rate Range: %u fps +/- %u fps\n",
2004 printf(" Nominal Frame Rate: %u fps\n", x
[0x12]);
2005 printf(" Color Bit Depth: %u @ interface, %u @ display\n",
2006 (x
[0x13] >> 4) + 1, (x
[0x13] & 0xf) + 1);
2009 printf(" Additional Primary Chromaticities:\n");
2010 unsigned col_x
= (x
[0x16] << 2) | (x
[0x14] >> 6);
2011 unsigned col_y
= (x
[0x17] << 2) | ((x
[0x14] >> 4) & 3);
2012 printf(" Primary 4: 0.%04u, 0.%04u\n",
2013 (col_x
* 10000) / 1024, (col_y
* 10000) / 1024);
2015 col_x
= (x
[0x18] << 2) | ((x
[0x14] >> 2) & 3);
2016 col_y
= (x
[0x19] << 2) | (x
[0x14] & 3);
2017 printf(" Primary 5: 0.%04u, 0.%04u\n",
2018 (col_x
* 10000) / 1024, (col_y
* 10000) / 1024);
2020 col_x
= (x
[0x1a] << 2) | (x
[0x15] >> 6);
2021 col_y
= (x
[0x1b] << 2) | ((x
[0x15] >> 4) & 3);
2022 printf(" Primary 6: 0.%04u, 0.%04u\n",
2023 (col_x
* 10000) / 1024, (col_y
* 10000) / 1024);
2029 printf(" Response Time %s: %u ms\n",
2030 (v
& 0x80) ? "White -> Black" : "Black -> White", v
& 0x7f);
2032 printf(" Overscan: %u%% x %u%%\n", v
>> 4, v
& 0xf);
2035 static double decode_uchar_as_double(unsigned char x
)
2037 signed char s
= (signed char)x
;
2042 void edid_state::cta_rcdb(const unsigned char *x
, unsigned length
)
2044 unsigned spm
= ((x
[3] << 16) | (x
[2] << 8) | x
[1]);
2048 fail("Empty Data Block with length %u.\n", length
);
2052 if ((x
[0] & 0x20) && !cta
.has_sldb
)
2053 fail("'SLD' flag is 1, but no Speaker Location Data Block is found.\n");
2054 else if (!(x
[0] & 0x20) && cta
.has_sldb
)
2055 fail("'SLD' flag is 0, but a Speaker Location Data Block is present.\n");
2058 printf(" Speaker count: %u\n", (x
[0] & 0x1f) + 1);
2061 fail("'Speaker' flag is 0, but 'Speaker Count' is != 0.\n");
2063 fail("'SLD' flag is 1, but 'Speaker' is 0.\n");
2066 printf(" Speaker Presence Mask:\n");
2067 for (i
= 0; cta_speaker_map
[i
]; i
++) {
2069 printf(" %s\n", cta_speaker_map
[i
]);
2072 if ((x
[0] & 0xa0) == 0x80)
2073 fail("'Display' flag set, but not the 'SLD' flag.\n");
2075 bool valid_max
= cta
.preparsed_sld_has_coord
|| (x
[0] & 0x80);
2077 if (valid_max
&& length
>= 7) {
2078 printf(" Xmax: %u dm\n", x
[4]);
2079 printf(" Ymax: %u dm\n", x
[5]);
2080 printf(" Zmax: %u dm\n", x
[6]);
2081 } else if (!valid_max
&& length
>= 7) {
2082 // The RCDB should have been truncated.
2083 warn("'Display' flag is 0 and 'Coord' is 0 for all SLDs, but the Max coordinates are still present.\n");
2085 if ((x
[0] & 0x80) && length
>= 10) {
2086 printf(" DisplayX: %.3f * Xmax\n", decode_uchar_as_double(x
[7]));
2087 printf(" DisplayY: %.3f * Ymax\n", decode_uchar_as_double(x
[8]));
2088 printf(" DisplayZ: %.3f * Zmax\n", decode_uchar_as_double(x
[9]));
2089 } else if (!(x
[0] & 0x80) && length
>= 10) {
2090 // The RCDB should have been truncated.
2091 warn("'Display' flag is 0, but the Display coordinates are still present.\n");
2095 static const struct {
2098 } speaker_location
[] = {
2099 { "FL - Front Left", -1, 1, 0 },
2100 { "FR - Front Right", 1, 1, 0 },
2101 { "FC - Front Center", 0, 1, 0 },
2102 { "LFE1 - Low Frequency Effects 1", -0.5, 1, -1 },
2103 { "BL - Back Left", -1, -1, 0 },
2104 { "BR - Back Right", 1, -1, 0 },
2105 { "FLC - Front Left of Center", -0.5, 1, 0 },
2106 { "FRC - Front Right of Center", 0.5, 1, 0 },
2107 { "BC - Back Center", 0, -1, 0 },
2108 { "LFE2 - Low Frequency Effects 2", 0.5, 1, -1 },
2109 { "SiL - Side Left", -1, 1.0/3.0, 0 },
2110 { "SiR - Side Right", 1, 1.0/3.0, 0 },
2111 { "TpFL - Top Front Left", -1, 1, 1 },
2112 { "TpFR - Top Front Right", 1, 1, 1 },
2113 { "TpFC - Top Front Center", 0, 1, 1 },
2114 { "TpC - Top Center", 0, 0, 1 },
2115 { "TpBL - Top Back Left", -1, -1, 1 },
2116 { "TpBR - Top Back Right", 1, -1, 1 },
2117 { "TpSiL - Top Side Left", -1, 0, 1 },
2118 { "TpSiR - Top Side Right", 1, 0, 1 },
2119 { "TpBC - Top Back Center", 0, -1, 1 },
2120 { "BtFC - Bottom Front Center", 0, 1, -1 },
2121 { "BtFL - Bottom Front Left", -1, 1, -1 },
2122 { "BtFR - Bottom Front Right", 1, 1, -1 },
2123 { "FLW - Front Left Wide", -1, 2.0/3.0, 0 },
2124 { "FRW - Front Right Wide", 1, 2.0/3.0, 0 },
2125 { "LS - Left Surround", -1, 0, 0 },
2126 { "RS - Right Surround", 1, 0, 0 },
2129 void edid_state::cta_sldb(const unsigned char *x
, unsigned length
)
2132 fail("Empty Data Block with length %u.\n", length
);
2136 unsigned active_cnt
= 0;
2137 unsigned channel_is_active
= 0;
2139 while (length
>= 2) {
2140 printf(" Channel: %u (%sactive)\n", x
[0] & 0x1f,
2141 (x
[0] & 0x20) ? "" : "not ");
2143 if (channel_is_active
& (1U << (x
[0] & 0x1f)))
2144 fail("Channel Index %u was already marked 'Active'.\n",
2146 channel_is_active
|= 1U << (x
[0] & 0x1f);
2150 unsigned speaker_id
= x
[1] & 0x1f;
2152 if (speaker_id
< ARRAY_SIZE(speaker_location
)) {
2153 printf(" Speaker ID: %s\n", speaker_location
[speaker_id
].name
);
2154 } else if (speaker_id
== 0x1f) {
2155 printf(" Speaker ID: None Specified\n");
2157 printf(" Speaker ID: Reserved (%u)\n", speaker_id
);
2158 fail("Reserved Speaker ID specified.\n");
2160 if (length
>= 5 && (x
[0] & 0x40)) {
2161 printf(" X: %.3f * Xmax\n", decode_uchar_as_double(x
[2]));
2162 printf(" Y: %.3f * Ymax\n", decode_uchar_as_double(x
[3]));
2163 printf(" Z: %.3f * Zmax\n", decode_uchar_as_double(x
[4]));
2166 } else if (speaker_id
< ARRAY_SIZE(speaker_location
)) {
2167 printf(" X: %.3f * Xmax (approximately)\n", speaker_location
[speaker_id
].x
);
2168 printf(" Y: %.3f * Ymax (approximately)\n", speaker_location
[speaker_id
].y
);
2169 printf(" Z: %.3f * Zmax (approximately)\n", speaker_location
[speaker_id
].z
);
2175 if (active_cnt
!= cta
.preparsed_speaker_count
)
2176 fail("There are %u active speakers, but 'Speaker Count' is %u.\n",
2177 active_cnt
, cta
.preparsed_speaker_count
);
2180 void edid_state::cta_preparse_sldb(const unsigned char *x
, unsigned length
)
2182 cta
.has_sldb
= true;
2183 while (length
>= 2) {
2184 if (length
>= 5 && (x
[0] & 0x40)) {
2185 cta
.preparsed_sld_has_coord
= true;
2193 void edid_state::cta_vcdb(const unsigned char *x
, unsigned length
)
2195 unsigned char d
= x
[0];
2197 cta
.has_vcdb
= true;
2199 fail("Empty Data Block with length %u.\n", length
);
2202 printf(" YCbCr quantization: %s\n",
2203 (d
& 0x80) ? "Selectable (via AVI YQ)" : "No Data");
2204 printf(" RGB quantization: %s\n",
2205 (d
& 0x40) ? "Selectable (via AVI Q)" : "No Data");
2207 * If this bit is not set then that will result in interoperability
2208 * problems (specifically with PCs/laptops) that quite often do not
2209 * follow the default rules with respect to RGB Quantization Range
2212 * Starting with the CTA-861-H spec this bit is now required to be
2213 * 1 for new designs.
2216 fail("Set Selectable RGB Quantization to avoid interop issues.\n");
2218 * Since most YCbCr formats use limited range, the interop issues are
2219 * less noticable than for RGB formats.
2221 * Starting with the CTA-861-H spec this bit is now required to be
2222 * 1 for new designs, but just warn about it (for now).
2224 if ((cta
.byte3
& 0x30) && !(d
& 0x80))
2225 warn("Set Selectable YCbCr Quantization to avoid interop issues.\n");
2227 unsigned char s_pt
= (d
>> 4) & 0x03;
2228 unsigned char s_it
= (d
>> 2) & 0x03;
2229 unsigned char s_ce
= d
& 0x03;
2231 printf(" PT scan behavior: ");
2233 case 0: printf("No Data\n"); break;
2234 case 1: printf("Always Overscanned\n"); break;
2235 case 2: printf("Always Underscanned\n"); break;
2236 case 3: printf("Supports both over- and underscan\n"); break;
2238 printf(" IT scan behavior: ");
2240 case 0: printf("IT video formats not supported\n"); break;
2242 printf("Always Overscanned\n");
2243 // See Table 52 of CTA-861-G for a description of Byte 3
2244 if (cta
.byte3
& 0x80)
2245 fail("IT video formats are always overscanned, but bit 7 of Byte 3 of the CTA-861 Extension header is set to underscanned.\n");
2248 printf("Always Underscanned\n");
2249 // See Table 52 of CTA-861-G for a description of Byte 3
2250 if (!(cta
.byte3
& 0x80))
2251 fail("IT video formats are always underscanned, but bit 7 of Byte 3 of the CTA-861 Extension header is set to overscanned.\n");
2253 case 3: printf("Supports both over- and underscan\n"); break;
2256 warn("IT scan behavior is expected to support underscanned.\n");
2257 printf(" CE scan behavior: ");
2259 case 0: printf("CE video formats not supported\n"); break;
2260 case 1: printf("Always Overscanned\n"); break;
2261 case 2: printf("Always Underscanned\n"); break;
2262 case 3: printf("Supports both over- and underscan\n"); break;
2265 warn("'CE video formats not supported' makes no sense.\n");
2266 else if (s_pt
== s_it
&& s_pt
== s_ce
)
2267 warn("S_PT is equal to S_IT and S_CE, so should be set to 0 instead.\n");
2270 static const char *colorimetry1_map
[] = {
2281 static const char *colorimetry2_map
[] = {
2282 "Gamut Boundary Description Metadata Profile P0",
2292 void edid_state::cta_colorimetry_block(const unsigned char *x
, unsigned length
)
2297 fail("Empty Data Block with length %u.\n", length
);
2300 for (i
= 0; i
< ARRAY_SIZE(colorimetry1_map
); i
++)
2301 if (x
[0] & (1 << i
))
2302 printf(" %s\n", colorimetry1_map
[i
]);
2303 // Bit MD0 is used to indicate if HDMI Gamut Boundary Description
2304 // Metadata Profile P0 is supported. Bits F41-F43 are reserved
2305 // and must be set to 0.
2307 fail("Reserved bits F41-F43 must be 0.\n");
2308 for (i
= 0; i
< ARRAY_SIZE(colorimetry2_map
); i
++)
2309 if (x
[1] & (1 << i
))
2310 printf(" %s\n", colorimetry2_map
[i
]);
2311 // The sRGB bit (added in CTA-861.6) allows sources to explicitly
2312 // signal sRGB colorimetry. Without this the default colorimetry
2313 // of an RGB video is either sRGB or defaultRGB. It depends on the
2314 // Source which is used, and the Sink has no idea what it is getting.
2316 // For proper compatibility with PCs enabling sRGB support is
2318 if (!base
.uses_srgb
&& !(x
[1] & 0x20))
2319 warn("Set the sRGB colorimetry bit to avoid interop issues.\n");
2321 cta
.avi_version
= 4;
2324 static const char *eotf_map
[] = {
2325 "Traditional gamma - SDR luminance range",
2326 "Traditional gamma - HDR luminance range",
2331 static void cta_hdr_static_metadata_block(const unsigned char *x
, unsigned length
)
2336 fail("Empty Data Block with length %u.\n", length
);
2339 printf(" Electro optical transfer functions:\n");
2340 for (i
= 0; i
< 6; i
++) {
2341 if (x
[0] & (1 << i
)) {
2342 if (i
< ARRAY_SIZE(eotf_map
)) {
2343 printf(" %s\n", eotf_map
[i
]);
2345 printf(" Unknown (%u)\n", i
);
2346 fail("Unknown EOTF (%u).\n", i
);
2350 printf(" Supported static metadata descriptors:\n");
2351 for (i
= 0; i
< 8; i
++) {
2352 if (x
[1] & (1 << i
))
2353 printf(" Static metadata type %u\n", i
+ 1);
2357 printf(" Desired content max luminance: %u (%.3f cd/m^2)\n",
2358 x
[2], 50.0 * pow(2, x
[2] / 32.0));
2361 printf(" Desired content max frame-average luminance: %u (%.3f cd/m^2)\n",
2362 x
[3], 50.0 * pow(2, x
[3] / 32.0));
2365 printf(" Desired content min luminance: %u (%.3f cd/m^2)\n",
2366 x
[4], (50.0 * pow(2, x
[2] / 32.0)) * pow(x
[4] / 255.0, 2) / 100.0);
2369 static void cta_hdr_dyn_metadata_block(const unsigned char *x
, unsigned length
)
2372 fail("Empty Data Block with length %u.\n", length
);
2375 while (length
>= 3) {
2376 unsigned type_len
= x
[0];
2377 unsigned type
= x
[1] | (x
[2] << 8);
2379 if (length
< type_len
+ 1)
2381 printf(" HDR Dynamic Metadata Type %u\n", type
);
2386 printf(" Version: %u\n", x
[3] & 0xf);
2390 unsigned version
= x
[3] & 0xf;
2391 printf(" Version: %u\n", version
);
2393 if (x
[3] & 0x10) printf(" Supports SL-HDR1 (ETSI TS 103 433-1)\n");
2394 if (x
[3] & 0x20) printf(" Supports SL-HDR2 (ETSI TS 103 433-2)\n");
2395 if (x
[3] & 0x40) printf(" Supports SL-HDR3 (ETSI TS 103 433-3)\n");
2402 length
-= type_len
+ 1;
2407 static const char *infoframe_types
[] = {
2410 "Auxiliary Video Information",
2411 "Source Product Description",
2415 "Dynamic Range and Mastering",
2418 static void cta_ifdb(const unsigned char *x
, unsigned length
)
2420 unsigned len_hdr
= x
[0] >> 5;
2423 fail("Empty Data Block with length %u.\n", length
);
2426 printf(" VSIFs: %u\n", x
[1]);
2427 if (length
< len_hdr
+ 2)
2429 length
-= len_hdr
+ 2;
2431 while (length
> 0) {
2432 int payload_len
= x
[0] >> 5;
2433 unsigned char type
= x
[0] & 0x1f;
2435 const char *name
= NULL
;
2436 if (type
< ARRAY_SIZE(infoframe_types
))
2437 name
= infoframe_types
[type
];
2440 printf(" %s InfoFrame (%u)", name
, type
);
2442 if (type
== 1 && length
>= 4) {
2443 unsigned oui
= (x
[3] << 16) | (x
[2] << 8) | x
[1];
2445 printf(", OUI %s\n", ouitohex(oui
).c_str());
2454 length
-= payload_len
;
2458 void edid_state::cta_pidb(const unsigned char *x
, unsigned length
)
2461 fail("Empty Data Block with length %u.\n", length
);
2464 unsigned oui
= (x
[0] << 16) | (x
[1] << 8) | x
[2];
2465 printf(" IEEE CID/OUI: %s\n", ouitohex(oui
).c_str());
2468 printf(" Version: %u\n", x
[3]);
2470 fail("Unsupported version %u.\n", x
[3]);
2474 memcpy(pn
, x
+ 4, length
- 5);
2476 for (unsigned i
= 0; i
< length
- 5; i
++)
2477 if (x
[4 + i
] < 0x20 || x
[4 + i
] >= 0x80)
2478 fail("Product Name: invalid ASCII value at position %u.\n", i
);
2479 printf(" Product Name: %s\n", pn
);
2482 void edid_state::cta_displayid_type_7(const unsigned char *x
, unsigned length
)
2484 check_displayid_datablock_revision(x
[0], 0x00, 2);
2486 if (length
< 21U + ((x
[0] & 0x70) >> 4)) {
2487 fail("Empty Data Block with length %u.\n", length
);
2490 parse_displayid_type_1_7_timing(x
+ 1, true, 2, true);
2493 void edid_state::cta_displayid_type_8(const unsigned char *x
, unsigned length
)
2495 check_displayid_datablock_revision(x
[0], 0xe8, 1);
2496 if (length
< ((x
[0] & 0x08) ? 3 : 2)) {
2497 fail("Empty Data Block with length %u.\n", length
);
2501 unsigned sz
= (x
[0] & 0x08) ? 2 : 1;
2502 unsigned type
= x
[0] >> 6;
2505 fail("Only code type 0 is supported.\n");
2510 printf(" Also supports YCbCr 4:2:0\n");
2514 for (unsigned i
= 0; i
< length
/ sz
; i
++) {
2515 unsigned id
= x
[i
* sz
];
2518 id
|= x
[i
* sz
+ 1] << 8;
2519 parse_displayid_type_4_8_timing(type
, id
, true);
2523 void edid_state::cta_displayid_type_10(const unsigned char *x
, unsigned length
)
2525 check_displayid_datablock_revision(x
[0], 0x70);
2526 if (length
< 7U + ((x
[0] & 0x70) >> 4)) {
2527 fail("Empty Data Block with length %u.\n", length
);
2531 unsigned sz
= 6U + ((x
[0] & 0x70) >> 4);
2534 for (unsigned i
= 0; i
< length
/ sz
; i
++)
2535 parse_displayid_type_10_timing(x
+ i
* sz
, sz
, true);
2538 static void cta_hdmi_audio_block(const unsigned char *x
, unsigned length
)
2543 fail("Empty Data Block with length %u.\n", length
);
2547 printf(" Max Stream Count: %u\n", (x
[0] & 3) + 1);
2549 printf(" Supports MS NonMixed\n");
2550 } else if (x
[0] & 4) {
2551 fail("MS NonMixed support indicated but Max Stream Count == 0.\n");
2554 num_descs
= x
[1] & 7;
2559 while (length
>= 4) {
2561 unsigned format
= x
[0] & 0xf;
2563 printf(" %s:\n", audio_format(format
).c_str());
2564 printf(" Max channels: %u\n", (x
[1] & 0x1f)+1);
2565 printf(" Supported sample rates (kHz):%s%s%s%s%s%s%s\n",
2566 (x
[2] & 0x40) ? " 192" : "",
2567 (x
[2] & 0x20) ? " 176.4" : "",
2568 (x
[2] & 0x10) ? " 96" : "",
2569 (x
[2] & 0x08) ? " 88.2" : "",
2570 (x
[2] & 0x04) ? " 48" : "",
2571 (x
[2] & 0x02) ? " 44.1" : "",
2572 (x
[2] & 0x01) ? " 32" : "");
2574 printf(" Supported sample sizes (bits):%s%s%s\n",
2575 (x
[3] & 0x04) ? " 24" : "",
2576 (x
[3] & 0x02) ? " 20" : "",
2577 (x
[3] & 0x01) ? " 16" : "");
2579 unsigned sad
= ((x
[2] << 16) | (x
[1] << 8) | x
[0]);
2582 switch (x
[3] >> 4) {
2584 printf(" Speaker Allocation for 10.2 channels:\n");
2587 printf(" Speaker Allocation for 22.2 channels:\n");
2590 printf(" Speaker Allocation for 30.2 channels:\n");
2593 printf(" Unknown Speaker Allocation (0x%02x)\n", x
[3] >> 4);
2597 for (i
= 0; cta_speaker_map
[i
]; i
++) {
2599 printf(" %s\n", cta_speaker_map
[i
]);
2607 void edid_state::cta_block(const unsigned char *x
, std::vector
<unsigned> &found_tags
)
2609 unsigned length
= x
[0] & 0x1f;
2610 unsigned tag
= (x
[0] & 0xe0) >> 5;
2611 unsigned extended
= (tag
== 0x07) ? 1 : 0;
2614 if (extended
&& length
) {
2621 bool dooutputname
= true;
2622 bool audio_block
= false;
2626 case 0x01: data_block
= "Audio Data Block"; audio_block
= true; break;
2627 case 0x02: data_block
= "Video Data Block"; break;
2628 case 0x03: data_block
= "Vendor-Specific Data Block"; break;
2629 case 0x04: data_block
= "Speaker Allocation Data Block"; audio_block
= true; break;
2630 case 0x05: data_block
= "VESA Display Transfer Characteristics Data Block"; break;
2631 case 0x06: data_block
= "Video Format Data Block"; break;
2632 case 0x07: data_block
= "Unknown CTA-861 Data Block (extended tag truncated)"; break;
2634 case 0x700: data_block
= "Video Capability Data Block"; break;
2635 case 0x701: data_block
= "Vendor-Specific Video Data Block"; break;
2636 case 0x702: data_block
= "VESA Video Display Device Data Block"; break;
2637 case 0x703: data_block
= "VESA Video Timing Block Extension"; break;
2638 case 0x704: data_block
= "Reserved for HDMI Video Data Block"; break;
2639 case 0x705: data_block
= "Colorimetry Data Block"; break;
2640 case 0x706: data_block
= "HDR Static Metadata Data Block"; break;
2641 case 0x707: data_block
= "HDR Dynamic Metadata Data Block"; break;
2642 case 0x708: data_block
= "Native Video Resolution Data Block"; break;
2644 case 0x70d: data_block
= "Video Format Preference Data Block"; break;
2645 case 0x70e: data_block
= "YCbCr 4:2:0 Video Data Block"; break;
2646 case 0x70f: data_block
= "YCbCr 4:2:0 Capability Map Data Block"; break;
2647 case 0x710: data_block
= "Reserved for CTA-861 Miscellaneous Audio Fields"; break;
2648 case 0x711: data_block
= "Vendor-Specific Audio Data Block"; audio_block
= true; break;
2649 case 0x712: data_block
= "HDMI Audio Data Block"; audio_block
= true; break;
2650 case 0x713: data_block
= "Room Configuration Data Block"; audio_block
= true; break;
2651 case 0x714: data_block
= "Speaker Location Data Block"; audio_block
= true; break;
2653 case 0x720: data_block
= "InfoFrame Data Block"; break;
2654 case 0x721: data_block
= "Product Information Data Block"; break;
2656 case 0x722: data_block
= "DisplayID Type VII Video Timing Data Block"; break;
2657 case 0x723: data_block
= "DisplayID Type VIII Video Timing Data Block"; break;
2658 case 0x72a: data_block
= "DisplayID Type X Video Timing Data Block"; break;
2660 case 0x778: data_block
= "HDMI Forum EDID Extension Override Data Block"; break;
2661 case 0x779: data_block
= "HDMI Forum Sink Capability Data Block"; break;
2662 case 0x77a: data_block
= "HDMI Forum Source-Based Tone Mapping Data Block"; break;
2665 std::string unknown_name
;
2666 if (tag
< 0x700) unknown_name
= "Unknown CTA-861 Data Block";
2667 else if (tag
< 0x70d) unknown_name
= "Unknown CTA-861 Video-Related Data Block";
2668 else if (tag
< 0x720) unknown_name
= "Unknown CTA-861 Audio-Related Data Block";
2669 else if (tag
< 0x778) unknown_name
= "Unknown CTA-861 Data Block";
2670 else if (tag
< 0x780) unknown_name
= "Unknown CTA-861 HDMI-Related Data Block";
2671 else unknown_name
= "Unknown CTA-861 Data Block";
2672 unknown_name
+= std::string(" (") + (extended
? "extended " : "") + "tag " + utohex(tag
& 0xff) + ", length " + std::to_string(length
) + ")";
2673 printf(" %s:\n", unknown_name
.c_str());
2674 warn("%s.\n", unknown_name
.c_str());
2684 data_block_oui(data_block
, x
, length
, &ouinum
);
2685 x
+= (length
< 3) ? length
: 3;
2686 length
-= (length
< 3) ? length
: 3;
2687 dooutputname
= false;
2693 if (dooutputname
&& data_block
.length())
2694 printf(" %s:\n", data_block
.c_str());
2712 if (std::find(found_tags
.begin(), found_tags
.end(), tag
) != found_tags
.end())
2713 fail("Only one instance of this Data Block is allowed.\n");
2717 // See Table 52 of CTA-861-G for a description of Byte 3
2718 if (audio_block
&& !(cta
.byte3
& 0x40))
2719 fail("Audio information is present, but bit 6 of Byte 3 of the CTA-861 Extension header indicates no Basic Audio support.\n");
2722 case 0x01: cta_audio_block(x
, length
); break;
2723 case 0x02: cta_svd(x
, length
, false); break;
2724 case 0x03|kOUI_HDMI
:
2725 cta_hdmi_block(x
, length
);
2726 // The HDMI OUI is present, so this EDID represents an HDMI
2727 // interface. And HDMI interfaces must use EDID version 1.3
2728 // according to the HDMI Specification, so check for this.
2729 if (base
.edid_minor
!= 3)
2730 fail("The HDMI Specification requires EDID 1.3 instead of 1.%u.\n",
2733 case 0x03|kOUI_HDMIForum
:
2734 if (cta
.previous_cta_tag
!= (0x03|kOUI_HDMI
))
2735 fail("HDMI Forum VSDB 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");
2738 cta_hf_scdb(x
, length
);
2739 cta
.have_hf_vsdb
= true;
2741 case 0x03|kOUI_AMD
: cta_amd(x
, length
); break;
2742 case 0x03|kOUI_Microsoft
: if (length
!= 0x12) goto dodefault
; cta_microsoft(x
, length
); break;
2743 case 0x03|kOUI_UHDA
: cta_uhda_fmm(x
, length
); break;
2744 case 0x04: cta_sadb(x
, length
); break;
2745 case 0x05: cta_vesa_dtcdb(x
, length
); break;
2746 case 0x06: cta_vfdb(x
, length
); break;
2747 case 0x07: fail("Extended tag cannot have zero length.\n"); break;
2748 case 0x700: cta_vcdb(x
, length
); break;
2749 case 0x701|kOUI_HDR10
: cta_hdr10plus(x
, length
); break;
2750 case 0x701|kOUI_Dolby
: cta_dolby_video(x
, length
); break;
2751 // 0x701|kOUI_Apple: this almost certainly contains 'BLC Info/Corrections',
2752 // since the data (spread out over two VSDBs) is very similar to what is seen
2753 // in DisplayID blocks. Since I don't know how to parse this data, we still
2754 // default to a hex dump, but I mention this here in case data on how to
2755 // parse this becomes available.
2756 case 0x702: cta_vesa_vdddb(x
, length
); break;
2757 case 0x705: cta_colorimetry_block(x
, length
); break;
2758 case 0x706: cta_hdr_static_metadata_block(x
, length
); break;
2759 case 0x707: cta_hdr_dyn_metadata_block(x
, length
); break;
2760 case 0x708: cta_nvrdb(x
, length
); return;
2761 case 0x70d: cta_vfpdb(x
, length
); break;
2762 case 0x70e: cta_svd(x
, length
, true); break;
2763 case 0x70f: cta_y420cmdb(x
, length
); break;
2764 case 0x711|kOUI_Dolby
: cta_dolby_audio(x
, length
); break;
2765 case 0x712: cta_hdmi_audio_block(x
, length
); break;
2766 case 0x713: cta_rcdb(x
, length
); break;
2767 case 0x714: cta_sldb(x
, length
); break;
2768 case 0x720: cta_ifdb(x
, length
); break;
2769 case 0x721: cta_pidb(x
, length
); break;
2770 case 0x722: cta_displayid_type_7(x
, length
); break;
2771 case 0x723: cta_displayid_type_8(x
, length
); break;
2772 case 0x72a: cta_displayid_type_10(x
, length
); break;
2774 cta_hf_eeodb(x
, length
);
2776 fail("Data Block can only be present in Block 1.\n");
2777 // This must be the first CTA-861 block
2778 if (cta
.block_number
> 0)
2779 fail("Data Block starts at a wrong offset.\n");
2782 if (cta
.previous_cta_tag
!= (0x03|kOUI_HDMI
))
2783 fail("HDMI Forum SCDB did not immediately follow the HDMI VSDB.\n");
2784 if (cta
.have_hf_scdb
|| cta
.have_hf_vsdb
)
2785 fail("Duplicate HDMI Forum VSDB/SCDB.\n");
2787 fail("Data Block can only be present in Block 1.\n");
2789 data_block
= std::string("HDMI Forum SCDB");
2790 fail("Invalid length %u < 2.\n", length
);
2794 printf(" Non-zero SCDB reserved fields!\n");
2795 cta_hf_scdb(x
+ 2, length
- 2);
2796 cta
.have_hf_scdb
= true;
2799 cta_hf_sbtmdb(x
, length
);
2803 hex_block(" ", x
, length
);
2808 cta
.previous_cta_tag
= tag
;
2809 found_tags
.push_back(tag
);
2812 void edid_state::preparse_cta_block(unsigned char *x
)
2814 unsigned version
= x
[1];
2815 unsigned offset
= x
[2];
2818 unsigned char *detailed
;
2819 bool update_checksum
= false;
2821 for (detailed
= x
+ offset
; detailed
+ 17 < x
+ 127; detailed
+= 18) {
2822 if (memchk(detailed
, 18))
2824 update_checksum
|= preparse_detailed_block(detailed
);
2825 if (detailed
[0] || detailed
[1])
2826 cta
.preparsed_total_dtds
++;
2828 if (update_checksum
)
2829 replace_checksum(x
, EDID_PAGE_SIZE
);
2835 for (unsigned i
= 4; i
< offset
; i
+= (x
[i
] & 0x1f) + 1) {
2836 bool for_ycbcr420
= false;
2839 switch ((x
[i
] & 0xe0) >> 5) {
2841 oui
= (x
[i
+ 3] << 16) + (x
[i
+ 2] << 8) + x
[i
+ 1];
2842 if (oui
== 0x000c03) {
2843 cta
.has_hdmi
= true;
2844 cta
.preparsed_phys_addr
= (x
[i
+ 4] << 8) | x
[i
+ 5];
2845 } else if ((oui
== 0xca125c || oui
== 0x5c12ca) &&
2846 (x
[i
] & 0x1f) == 0x15 && replace_unique_ids
) {
2847 memset(x
+ i
+ 6, 0, 16);
2848 replace_checksum(x
, EDID_PAGE_SIZE
);
2852 if (!(x
[i
] & 0x1f) || cta
.preparsed_first_vfd
.rid
)
2854 cta
.preparsed_first_vfd
= cta_parse_vfd(x
+ i
+ 2, (x
[i
+ 1] & 3) + 1);
2857 if (x
[i
+ 1] == 0x0d)
2858 cta
.has_vfpdb
= true;
2859 else if (x
[i
+ 1] == 0x05)
2861 else if (x
[i
+ 1] == 0x08)
2862 cta
.has_nvrdb
= true;
2863 else if (x
[i
+ 1] == 0x21)
2864 cta
.has_pidb
= true;
2865 else if (x
[i
+ 1] == 0x13 && (x
[i
+ 2] & 0x40)) {
2866 cta
.preparsed_speaker_count
= 1 + (x
[i
+ 2] & 0x1f);
2867 cta
.preparsed_sld
= x
[i
+ 2] & 0x20;
2868 } else if (x
[i
+ 1] == 0x14)
2869 cta_preparse_sldb(x
+ i
+ 2, (x
[i
] & 0x1f) - 1);
2870 else if (x
[i
+ 1] == 0x22)
2871 cta
.preparsed_total_vtdbs
++;
2872 else if (x
[i
+ 1] == 0x23) {
2873 cta
.preparsed_has_t8vtdb
= true;
2874 cta
.preparsed_t8vtdb_dmt
= x
[i
+ 3];
2875 if (x
[i
+ 2] & 0x08)
2876 cta
.preparsed_t8vtdb_dmt
|= x
[i
+ 4] << 8;
2877 } else if (x
[i
+ 1] == 0x2a)
2878 cta
.preparsed_total_vtdbs
+=
2879 ((x
[i
] & 0x1f) - 2) / (6 + ((x
[i
+ 2] & 0x70) >> 4));
2880 else if (x
[i
+ 1] == 0x78)
2881 cta
.hf_eeodb_blocks
= x
[i
+ 2];
2882 if (x
[i
+ 1] != 0x0e)
2884 for_ycbcr420
= true;
2885 #ifdef __EMSCRIPTEN__
2886 [[clang::fallthrough
]];
2890 for (unsigned j
= 1 + for_ycbcr420
; j
<= (x
[i
] & 0x1f); j
++) {
2891 unsigned char vic
= x
[i
+ j
];
2893 if ((vic
& 0x7f) <= 64)
2895 cta
.preparsed_svds
[for_ycbcr420
].push_back(vic
);
2896 cta
.preparsed_has_vic
[for_ycbcr420
][vic
] = true;
2898 const struct timings
*t
= find_vic_id(vic
);
2900 if (!for_ycbcr420
&& t
&&
2901 t
->pixclk_khz
> cta
.preparsed_max_vic_pixclk_khz
)
2902 cta
.preparsed_max_vic_pixclk_khz
= t
->pixclk_khz
;
2909 void edid_state::parse_cta_block(const unsigned char *x
)
2911 unsigned version
= x
[1];
2912 unsigned offset
= x
[2];
2913 const unsigned char *detailed
;
2915 // See Table 52 of CTA-861-G for a description of Byte 3
2917 printf(" Revision: %u\n", version
);
2919 fail("Invalid CTA-861 Extension revision 0.\n");
2921 fail("Deprecated CTA-861 Extension revision 2.\n");
2922 if (cta
.has_hdmi
&& version
!= 3)
2923 fail("The HDMI Specification requires CTA Extension revision 3.\n");
2925 warn("Unknown CTA-861 Extension revision %u.\n", version
);
2926 if (offset
> 0 && offset
< 4)
2927 fail("Invalid CTA-861 Extension offset value (byte 2).\n");
2929 if (version
>= 1) do {
2930 if (version
== 1 && x
[3] != 0)
2931 fail("Non-zero byte 3.\n");
2933 if (version
< 3 && offset
>= 4 && ((offset
- 4) / 8)) {
2934 printf(" 8-byte timing descriptors: %u\n", (offset
- 4) / 8);
2935 fail("8-byte descriptors were never used.\n");
2940 printf(" Underscans IT Video Formats by default\n");
2942 warn("IT Video Formats are overscanned by default, but normally this should be underscanned.\n");
2944 printf(" Basic audio support\n");
2946 printf(" Supports YCbCr 4:4:4\n");
2947 cta
.has_ycbcr444
= true;
2950 printf(" Supports YCbCr 4:2:2\n");
2951 cta
.has_ycbcr422
= true;
2953 // Disable this test: this fails a lot of EDIDs, and there are
2954 // also some corner cases where you only want to receive 4:4:4
2955 // and refuse a fallback to 4:2:2.
2956 // if ((x[3] & 0x30) && (x[3] & 0x30) != 0x30)
2957 // msg(!cta.has_hdmi, "If YCbCr support is indicated, then both 4:2:2 and 4:4:4 %s be supported.\n",
2958 // cta.has_hdmi ? "shall" : "should");
2959 printf(" Native detailed modes: %u\n", x
[3] & 0x0f);
2960 if (cta
.block_number
== 0)
2962 else if (x
[3] != cta
.byte3
)
2963 fail("Byte 3 must be the same for all CTA-861 Extension Blocks.\n");
2964 if (cta
.block_number
== 0) {
2965 unsigned native_dtds
= x
[3] & 0x0f;
2967 cta
.native_timings
.clear();
2968 if (!native_dtds
&& !cta
.has_vfpdb
) {
2969 cta
.first_svd_might_be_preferred
= true;
2970 } else if (native_dtds
> cta
.preparsed_total_dtds
) {
2971 fail("There are more Native DTDs (%u) than DTDs (%u).\n",
2972 native_dtds
, cta
.preparsed_total_dtds
);
2974 if (native_dtds
> cta
.preparsed_total_dtds
)
2975 native_dtds
= cta
.preparsed_total_dtds
;
2976 for (unsigned i
= 0; i
< native_dtds
; i
++) {
2979 sprintf(type
, "DTD %3u", i
+ 1);
2980 cta
.native_timings
.push_back(timings_ext(i
+ 129, type
));
2981 cta
.has_svrs
= true;
2983 if (cta
.has_hdmi
&& block_nr
!= (block_map
.saw_block_1
? 2 : 1))
2984 fail("The HDMI Specification requires that the first Extension Block (that is not a Block Map) is an CTA-861 Extension Block.\n");
2989 // Offset 0 means that there are no data blocks or DTDs,
2990 // so the remainder must be padding.
2991 if (!memchk(x
+ 4, 127 - 4)) {
2992 data_block
= "Padding";
2993 fail("Contains non-zero bytes.\n");
3001 for (i
= 4; i
< offset
; i
+= (x
[i
] & 0x1f) + 1) {
3002 cta_block(x
+ i
, cta
.found_tags
);
3007 fail("Offset is %u, but should be %u.\n", offset
, i
);
3010 data_block
= "Detailed Timing Descriptors";
3011 base
.seen_non_detailed_descriptor
= false;
3013 for (detailed
= x
+ offset
; detailed
+ 17 < x
+ 127; detailed
+= 18) {
3014 if (memchk(detailed
, 18))
3018 printf(" %s:\n", data_block
.c_str());
3020 detailed_block(detailed
);
3022 unused_bytes
= x
+ 127 - detailed
;
3023 if (!memchk(detailed
, unused_bytes
)) {
3024 data_block
= "Padding";
3025 fail("Contains non-zero bytes.\n");
3030 if (base
.serial_number
&& serial_strings
.size())
3031 warn("Display Product Serial Number is set, so the Serial Number in the Base EDID should be 0.\n");
3032 if (!cta
.has_vic_1
&& !base
.has_640x480p60_est_timing
)
3033 fail("Required 640x480p60 timings are missing in the established timings"
3034 " and the SVD list (VIC 1).\n");
3035 if ((cta
.supported_hdmi_vic_vsb_codes
& cta
.supported_hdmi_vic_codes
) !=
3036 cta
.supported_hdmi_vic_codes
)
3037 fail("HDMI VIC Codes must have their CTA-861 VIC equivalents in the VSB.\n");
3039 fail("Missing VCDB, needed for Set Selectable RGB Quantization to avoid interop issues.\n");
3040 if (!base
.uses_srgb
&& !cta
.has_cdb
)
3041 warn("Add a Colorimetry Data Block with the sRGB colorimetry bit set to avoid interop issues.\n");
3044 void edid_state::cta_resolve_svr(timings_ext
&t_ext
)
3046 if (t_ext
.svr() == 254) {
3047 t_ext
.flags
= cta
.t8vtdb
.flags
;
3048 add_str(t_ext
.flags
, ">=CTA-861-H");
3049 t_ext
.t
= cta
.t8vtdb
.t
;
3050 } else if (t_ext
.svr() <= 144) {
3051 if (t_ext
.svr() < 129 || t_ext
.svr() - 129 >= cta
.vec_dtds
.size())
3053 t_ext
.flags
= cta
.vec_dtds
[t_ext
.svr() - 129].flags
;
3054 t_ext
.t
= cta
.vec_dtds
[t_ext
.svr() - 129].t
;
3055 } else if (t_ext
.svr() <= 160) {
3056 if (t_ext
.svr() - 145 >= cta
.vec_vtdbs
.size())
3058 t_ext
.flags
= cta
.vec_vtdbs
[t_ext
.svr() - 145].flags
;
3059 add_str(t_ext
.flags
, ">=CTA-861-H");
3060 t_ext
.t
= cta
.vec_vtdbs
[t_ext
.svr() - 145].t
;
3061 } else if (t_ext
.svr() <= 175) {
3062 t_ext
.flags
.clear();
3063 unsigned char rid
= cta
.preparsed_first_vfd
.rid
;
3064 t_ext
.t
= calc_ovt_mode(rids
[rid
].hact
, rids
[rid
].vact
,
3065 rids
[rid
].hratio
, rids
[rid
].vratio
,
3066 vf_rate_values
[t_ext
.svr() - 160]);
3067 t_ext
.flags
= ">=CTA-861.6";
3071 void edid_state::cta_resolve_svrs()
3073 for (vec_timings_ext::iterator iter
= cta
.preferred_timings_vfpdb
.begin();
3074 iter
!= cta
.preferred_timings_vfpdb
.end(); ++iter
) {
3075 if (iter
->has_svr())
3076 cta_resolve_svr(*iter
);
3079 for (vec_timings_ext::iterator iter
= cta
.native_timings
.begin();
3080 iter
!= cta
.native_timings
.end(); ++iter
) {
3081 if (iter
->has_svr())
3082 cta_resolve_svr(*iter
);
3085 for (vec_timings_ext::iterator iter
= cta
.native_timing_nvrdb
.begin();
3086 iter
!= cta
.native_timing_nvrdb
.end(); ++iter
) {
3087 if (iter
->has_svr())
3088 cta_resolve_svr(*iter
);
3092 void edid_state::check_cta_blocks()
3094 unsigned max_pref_prog_hact
= 0;
3095 unsigned max_pref_prog_vact
= 0;
3096 unsigned max_pref_ilace_hact
= 0;
3097 unsigned max_pref_ilace_vact
= 0;
3099 data_block
= "CTA-861";
3101 // HDMI 1.4 goes up to 340 MHz. Dubious to have a DTD above that,
3102 // but no VICs. Displays often have a setting to turn off HDMI 2.x
3103 // support, dropping any HDMI 2.x VICs, but they sometimes forget
3104 // to replace the DTD in the base block as well.
3105 if (cta
.warn_about_hdmi_2x_dtd
)
3106 warn("DTD pixelclock indicates HDMI 2.x support, VICs indicate HDMI 1.x.\n");
3108 if (cta
.hdmi_max_rate
&& max_pixclk_khz
> cta
.hdmi_max_rate
* 1000)
3109 fail("The maximum HDMI TMDS clock is %u kHz, but one or more video timings go up to %u kHz.\n",
3110 cta
.hdmi_max_rate
* 1000, max_pixclk_khz
);
3112 for (vec_timings_ext::iterator iter
= cta
.preferred_timings
.begin();
3113 iter
!= cta
.preferred_timings
.end(); ++iter
) {
3114 if (iter
->t
.interlaced
&&
3115 (iter
->t
.vact
> max_pref_ilace_vact
||
3116 (iter
->t
.vact
== max_pref_ilace_vact
&& iter
->t
.hact
>= max_pref_ilace_hact
))) {
3117 max_pref_ilace_hact
= iter
->t
.hact
;
3118 max_pref_ilace_vact
= iter
->t
.vact
;
3120 if (!iter
->t
.interlaced
&&
3121 (iter
->t
.vact
> max_pref_prog_vact
||
3122 (iter
->t
.vact
== max_pref_prog_vact
&& iter
->t
.hact
>= max_pref_prog_hact
))) {
3123 max_pref_prog_hact
= iter
->t
.hact
;
3124 max_pref_prog_vact
= iter
->t
.vact
;
3127 for (vec_timings_ext::iterator iter
= cta
.preferred_timings_vfpdb
.begin();
3128 iter
!= cta
.preferred_timings_vfpdb
.end(); ++iter
) {
3129 if (iter
->t
.interlaced
&&
3130 (iter
->t
.vact
> max_pref_ilace_vact
||
3131 (iter
->t
.vact
== max_pref_ilace_vact
&& iter
->t
.hact
>= max_pref_ilace_hact
))) {
3132 max_pref_ilace_hact
= iter
->t
.hact
;
3133 max_pref_ilace_vact
= iter
->t
.vact
;
3135 if (!iter
->t
.interlaced
&&
3136 (iter
->t
.vact
> max_pref_prog_vact
||
3137 (iter
->t
.vact
== max_pref_prog_vact
&& iter
->t
.hact
>= max_pref_prog_hact
))) {
3138 max_pref_prog_hact
= iter
->t
.hact
;
3139 max_pref_prog_vact
= iter
->t
.vact
;
3143 unsigned native_prog
= 0;
3144 unsigned native_prog_hact
= 0;
3145 unsigned native_prog_vact
= 0;
3146 bool native_prog_mixed_resolutions
= false;
3147 unsigned native_ilace
= 0;
3148 unsigned native_ilace_hact
= 0;
3149 unsigned native_ilace_vact
= 0;
3150 bool native_ilace_mixed_resolutions
= false;
3151 unsigned native_nvrdb_hact
= 0;
3152 unsigned native_nvrdb_vact
= 0;
3154 for (vec_timings_ext::iterator iter
= cta
.native_timings
.begin();
3155 iter
!= cta
.native_timings
.end(); ++iter
) {
3156 if (iter
->t
.interlaced
) {
3158 if (!native_ilace_hact
) {
3159 native_ilace_hact
= iter
->t
.hact
;
3160 native_ilace_vact
= iter
->t
.vact
;
3161 } else if (native_ilace_hact
!= iter
->t
.hact
||
3162 native_ilace_vact
!= iter
->t
.vact
) {
3163 native_ilace_mixed_resolutions
= true;
3167 if (!native_prog_hact
) {
3168 native_prog_hact
= iter
->t
.hact
;
3169 native_prog_vact
= iter
->t
.vact
;
3170 } else if (native_prog_hact
!= iter
->t
.hact
||
3171 native_prog_vact
!= iter
->t
.vact
) {
3172 native_prog_mixed_resolutions
= true;
3177 for (vec_timings_ext::iterator iter
= cta
.native_timing_nvrdb
.begin();
3178 iter
!= cta
.native_timing_nvrdb
.end(); ++iter
) {
3179 native_nvrdb_hact
= iter
->t
.hact
;
3180 native_nvrdb_vact
= iter
->t
.vact
;
3183 if (native_prog_mixed_resolutions
)
3184 fail("Native progressive timings are a mix of several resolutions.\n");
3185 if (native_ilace_mixed_resolutions
)
3186 fail("Native interlaced timings are a mix of several resolutions.\n");
3187 if (native_ilace
&& !native_prog
)
3188 fail("A native interlaced timing is present, but not a native progressive timing.\n");
3189 if (!native_prog_mixed_resolutions
&& native_prog
> 1)
3190 warn("Multiple native progressive timings are defined.\n");
3191 if (!native_ilace_mixed_resolutions
&& native_ilace
> 1)
3192 warn("Multiple native interlaced timings are defined.\n");
3194 if (native_nvrdb_vact
&&
3195 (max_pref_prog_vact
> native_nvrdb_vact
||
3196 (max_pref_prog_vact
== native_nvrdb_vact
&& max_pref_prog_hact
> native_nvrdb_hact
)))
3197 warn("Native video resolution of %ux%u is smaller than the max preferred progressive resolution %ux%u.\n",
3198 native_nvrdb_hact
, native_nvrdb_vact
,
3199 max_pref_prog_hact
, max_pref_prog_vact
);
3200 else if (!native_nvrdb_vact
&& !native_prog_mixed_resolutions
&& native_prog_vact
&&
3201 (max_pref_prog_vact
> native_prog_vact
||
3202 (max_pref_prog_vact
== native_prog_vact
&& max_pref_prog_hact
> native_prog_hact
)))
3203 warn("Native progressive resolution of %ux%u is smaller than the max preferred progressive resolution %ux%u.\n",
3204 native_prog_hact
, native_prog_vact
,
3205 max_pref_prog_hact
, max_pref_prog_vact
);
3206 if (!native_ilace_mixed_resolutions
&& native_ilace_vact
&&
3207 (max_pref_ilace_vact
> native_ilace_vact
||
3208 (max_pref_ilace_vact
== native_ilace_vact
&& max_pref_ilace_hact
> native_ilace_hact
)))
3209 warn("Native interlaced resolution of %ux%u is smaller than the max preferred interlaced resolution %ux%u.\n",
3210 native_ilace_hact
, native_ilace_vact
,
3211 max_pref_ilace_hact
, max_pref_ilace_vact
);
3213 if (dispid
.native_width
&& native_prog_hact
&&
3214 !native_prog_mixed_resolutions
) {
3215 if (dispid
.native_width
!= native_prog_hact
||
3216 dispid
.native_height
!= native_prog_vact
)
3217 fail("Mismatch between CTA-861 and DisplayID native progressive resolution.\n");