edid.c revision 1.3.12.3 1 1.3.12.3 yamt /* $NetBSD: edid.c,v 1.3.12.3 2007/09/03 14:39:29 yamt Exp $ */
2 1.3.12.2 yamt
3 1.3.12.2 yamt /*-
4 1.3.12.2 yamt * Copyright (c) 2006 Itronix Inc.
5 1.3.12.2 yamt * All rights reserved.
6 1.3.12.2 yamt *
7 1.3.12.2 yamt * Written by Garrett D'Amore for Itronix Inc.
8 1.3.12.2 yamt *
9 1.3.12.2 yamt * Redistribution and use in source and binary forms, with or without
10 1.3.12.2 yamt * modification, are permitted provided that the following conditions
11 1.3.12.2 yamt * are met:
12 1.3.12.2 yamt * 1. Redistributions of source code must retain the above copyright
13 1.3.12.2 yamt * notice, this list of conditions and the following disclaimer.
14 1.3.12.2 yamt * 2. Redistributions in binary form must reproduce the above copyright
15 1.3.12.2 yamt * notice, this list of conditions and the following disclaimer in the
16 1.3.12.2 yamt * documentation and/or other materials provided with the distribution.
17 1.3.12.2 yamt * 3. The name of Itronix Inc. may not be used to endorse
18 1.3.12.2 yamt * or promote products derived from this software without specific
19 1.3.12.2 yamt * prior written permission.
20 1.3.12.2 yamt *
21 1.3.12.2 yamt * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND ANY EXPRESS
22 1.3.12.2 yamt * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 1.3.12.2 yamt * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 1.3.12.2 yamt * ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
25 1.3.12.2 yamt * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 1.3.12.2 yamt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27 1.3.12.2 yamt * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 1.3.12.2 yamt * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 1.3.12.2 yamt * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 1.3.12.2 yamt * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 1.3.12.2 yamt * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 1.3.12.2 yamt */
33 1.3.12.2 yamt
34 1.3.12.2 yamt #include <sys/cdefs.h>
35 1.3.12.3 yamt __KERNEL_RCSID(0, "$NetBSD: edid.c,v 1.3.12.3 2007/09/03 14:39:29 yamt Exp $");
36 1.3.12.2 yamt
37 1.3.12.2 yamt #include <sys/param.h>
38 1.3.12.2 yamt #include <sys/systm.h>
39 1.3.12.2 yamt #include <sys/device.h>
40 1.3.12.2 yamt #include <sys/kernel.h>
41 1.3.12.2 yamt #include <sys/malloc.h>
42 1.3.12.2 yamt #include <dev/videomode/videomode.h>
43 1.3.12.2 yamt #include <dev/videomode/ediddevs.h>
44 1.3.12.2 yamt #include <dev/videomode/edidreg.h>
45 1.3.12.2 yamt #include <dev/videomode/edidvar.h>
46 1.3.12.2 yamt #include <dev/videomode/vesagtf.h>
47 1.3.12.2 yamt
48 1.3.12.2 yamt #define EDIDVERBOSE 1
49 1.3.12.2 yamt #define DIVIDE(x,y) (((x) + ((y) / 2)) / (y))
50 1.3.12.2 yamt
51 1.3.12.2 yamt static const char *_edid_modes[] = {
52 1.3.12.2 yamt "1280x1024x75",
53 1.3.12.2 yamt "1024x768x75",
54 1.3.12.2 yamt "1024x768x70",
55 1.3.12.2 yamt "1024x768x60",
56 1.3.12.2 yamt "1024x768x87i",
57 1.3.12.2 yamt "832x768x74", /* rounding error, 74.55 Hz aka "832x624x75" */
58 1.3.12.2 yamt "800x600x75",
59 1.3.12.2 yamt "800x600x72",
60 1.3.12.2 yamt "800x600x60",
61 1.3.12.2 yamt "800x600x56",
62 1.3.12.2 yamt "640x480x75",
63 1.3.12.2 yamt "640x480x72",
64 1.3.12.2 yamt "640x480x67",
65 1.3.12.2 yamt "640x480x60",
66 1.3.12.2 yamt "720x400x85", /* should this really be "720x400x88" ? */
67 1.3.12.2 yamt "720x400x70", /* hmm... videmode.c doesn't have this one */
68 1.3.12.2 yamt };
69 1.3.12.2 yamt
70 1.3.12.2 yamt #ifdef EDIDVERBOSE
71 1.3.12.2 yamt struct edid_vendor {
72 1.3.12.2 yamt const char *vendor;
73 1.3.12.2 yamt const char *name;
74 1.3.12.2 yamt };
75 1.3.12.2 yamt
76 1.3.12.2 yamt struct edid_product {
77 1.3.12.2 yamt const char *vendor;
78 1.3.12.2 yamt uint16_t product;
79 1.3.12.2 yamt const char *name;
80 1.3.12.2 yamt };
81 1.3.12.2 yamt
82 1.3.12.2 yamt #include <dev/videomode/ediddevs_data.h>
83 1.3.12.2 yamt #endif /* EDIDVERBOSE */
84 1.3.12.2 yamt
85 1.3.12.2 yamt static const char *
86 1.3.12.2 yamt edid_findvendor(const char *vendor)
87 1.3.12.2 yamt {
88 1.3.12.2 yamt #ifdef EDIDVERBOSE
89 1.3.12.2 yamt int n;
90 1.3.12.2 yamt
91 1.3.12.2 yamt for (n = 0; n < edid_nvendors; n++)
92 1.3.12.2 yamt if (memcmp(edid_vendors[n].vendor, vendor, 3) == 0)
93 1.3.12.2 yamt return (edid_vendors[n].name);
94 1.3.12.2 yamt #endif
95 1.3.12.2 yamt return NULL;
96 1.3.12.2 yamt }
97 1.3.12.2 yamt
98 1.3.12.2 yamt static const char *
99 1.3.12.2 yamt edid_findproduct(const char *vendor, uint16_t product)
100 1.3.12.2 yamt {
101 1.3.12.2 yamt #ifdef EDIDVERBOSE
102 1.3.12.2 yamt int n;
103 1.3.12.2 yamt
104 1.3.12.2 yamt for (n = 0; n < edid_nvendors; n++)
105 1.3.12.2 yamt if ((edid_products[n].product == product) &&
106 1.3.12.2 yamt (memcmp(edid_products[n].vendor, vendor, 3) == 0))
107 1.3.12.2 yamt return (edid_products[n].name);
108 1.3.12.2 yamt #endif /* EDIDVERBOSE */
109 1.3.12.2 yamt return NULL;
110 1.3.12.2 yamt
111 1.3.12.2 yamt }
112 1.3.12.2 yamt
113 1.3.12.2 yamt static void
114 1.3.12.2 yamt edid_strchomp(char *ptr)
115 1.3.12.2 yamt {
116 1.3.12.2 yamt for (;;) {
117 1.3.12.2 yamt switch (*ptr) {
118 1.3.12.2 yamt case 0:
119 1.3.12.2 yamt return;
120 1.3.12.2 yamt case '\r':
121 1.3.12.2 yamt case '\n':
122 1.3.12.2 yamt *ptr = 0;
123 1.3.12.2 yamt return;
124 1.3.12.2 yamt }
125 1.3.12.2 yamt ptr++;
126 1.3.12.2 yamt }
127 1.3.12.2 yamt }
128 1.3.12.2 yamt
129 1.3.12.2 yamt int
130 1.3.12.2 yamt edid_is_valid(uint8_t *d)
131 1.3.12.2 yamt {
132 1.3.12.2 yamt int sum = 0, i;
133 1.3.12.2 yamt uint8_t sig[8] = EDID_SIGNATURE;
134 1.3.12.2 yamt
135 1.3.12.2 yamt if (memcmp(d, sig, 8) != 0)
136 1.3.12.2 yamt return EINVAL;
137 1.3.12.2 yamt
138 1.3.12.2 yamt for (i = 0; i < 128; i++)
139 1.3.12.2 yamt sum += d[i];
140 1.3.12.2 yamt if ((sum & 0xff) != 0)
141 1.3.12.2 yamt return EINVAL;
142 1.3.12.2 yamt
143 1.3.12.2 yamt return 0;
144 1.3.12.2 yamt }
145 1.3.12.2 yamt
146 1.3.12.2 yamt void
147 1.3.12.2 yamt edid_print(struct edid_info *edid)
148 1.3.12.2 yamt {
149 1.3.12.2 yamt int i;
150 1.3.12.2 yamt
151 1.3.12.2 yamt if (edid == NULL)
152 1.3.12.2 yamt return;
153 1.3.12.2 yamt printf("Vendor: [%s] %s\n", edid->edid_vendor, edid->edid_vendorname);
154 1.3.12.2 yamt printf("Product: [%04X] %s\n", edid->edid_product,
155 1.3.12.2 yamt edid->edid_productname);
156 1.3.12.2 yamt printf("Serial number: %s\n", edid->edid_serial);
157 1.3.12.2 yamt printf("Manufactured %d Week %d\n",
158 1.3.12.2 yamt edid->edid_year, edid->edid_week);
159 1.3.12.2 yamt printf("EDID Version %d.%d\n", edid->edid_version,
160 1.3.12.2 yamt edid->edid_revision);
161 1.3.12.2 yamt printf("EDID Comment: %s\n", edid->edid_comment);
162 1.3.12.2 yamt
163 1.3.12.2 yamt printf("Video Input: %x\n", edid->edid_video_input);
164 1.3.12.2 yamt if (edid->edid_video_input & EDID_VIDEO_INPUT_DIGITAL) {
165 1.3.12.2 yamt printf("\tDigital");
166 1.3.12.2 yamt if (edid->edid_video_input & EDID_VIDEO_INPUT_DFP1_COMPAT)
167 1.3.12.2 yamt printf(" (DFP 1.x compatible)");
168 1.3.12.2 yamt printf("\n");
169 1.3.12.2 yamt } else {
170 1.3.12.2 yamt printf("\tAnalog\n");
171 1.3.12.2 yamt switch (EDID_VIDEO_INPUT_LEVEL(edid->edid_video_input)) {
172 1.3.12.2 yamt case 0:
173 1.3.12.2 yamt printf("\t-0.7, 0.3V\n");
174 1.3.12.2 yamt break;
175 1.3.12.2 yamt case 1:
176 1.3.12.2 yamt printf("\t-0.714, 0.286V\n");
177 1.3.12.2 yamt break;
178 1.3.12.2 yamt case 2:
179 1.3.12.2 yamt printf("\t-1.0, 0.4V\n");
180 1.3.12.2 yamt break;
181 1.3.12.2 yamt case 3:
182 1.3.12.2 yamt printf("\t-0.7, 0.0V\n");
183 1.3.12.2 yamt break;
184 1.3.12.2 yamt }
185 1.3.12.2 yamt if (edid->edid_video_input & EDID_VIDEO_INPUT_BLANK_TO_BLACK)
186 1.3.12.2 yamt printf("\tBlank-to-black setup\n");
187 1.3.12.2 yamt if (edid->edid_video_input & EDID_VIDEO_INPUT_SEPARATE_SYNCS)
188 1.3.12.2 yamt printf("\tSeperate syncs\n");
189 1.3.12.2 yamt if (edid->edid_video_input & EDID_VIDEO_INPUT_COMPOSITE_SYNC)
190 1.3.12.2 yamt printf("\tComposite sync\n");
191 1.3.12.2 yamt if (edid->edid_video_input & EDID_VIDEO_INPUT_SYNC_ON_GRN)
192 1.3.12.2 yamt printf("\tSync on green\n");
193 1.3.12.2 yamt if (edid->edid_video_input & EDID_VIDEO_INPUT_SERRATION)
194 1.3.12.2 yamt printf("\tSerration vsync\n");
195 1.3.12.2 yamt }
196 1.3.12.2 yamt
197 1.3.12.2 yamt printf("Gamma: %d.%02d\n",
198 1.3.12.2 yamt edid->edid_gamma / 100, edid->edid_gamma % 100);
199 1.3.12.2 yamt
200 1.3.12.2 yamt printf("Max Size: %d cm x %d cm\n",
201 1.3.12.2 yamt edid->edid_max_hsize, edid->edid_max_vsize);
202 1.3.12.2 yamt
203 1.3.12.2 yamt printf("Features: %x\n", edid->edid_features);
204 1.3.12.2 yamt if (edid->edid_features & EDID_FEATURES_STANDBY)
205 1.3.12.2 yamt printf("\tDPMS standby\n");
206 1.3.12.2 yamt if (edid->edid_features & EDID_FEATURES_SUSPEND)
207 1.3.12.2 yamt printf("\tDPMS suspend\n");
208 1.3.12.2 yamt if (edid->edid_features & EDID_FEATURES_ACTIVE_OFF)
209 1.3.12.2 yamt printf("\tDPMS active-off\n");
210 1.3.12.2 yamt switch (EDID_FEATURES_DISP_TYPE(edid->edid_features)) {
211 1.3.12.2 yamt case EDID_FEATURES_DISP_TYPE_MONO:
212 1.3.12.2 yamt printf("\tMonochrome\n");
213 1.3.12.2 yamt break;
214 1.3.12.2 yamt case EDID_FEATURES_DISP_TYPE_RGB:
215 1.3.12.2 yamt printf("\tRGB\n");
216 1.3.12.2 yamt break;
217 1.3.12.2 yamt case EDID_FEATURES_DISP_TYPE_NON_RGB:
218 1.3.12.2 yamt printf("\tMulticolor\n");
219 1.3.12.2 yamt break;
220 1.3.12.2 yamt case EDID_FEATURES_DISP_TYPE_UNDEFINED:
221 1.3.12.2 yamt printf("\tUndefined monitor type\n");
222 1.3.12.2 yamt break;
223 1.3.12.2 yamt }
224 1.3.12.2 yamt if (edid->edid_features & EDID_FEATURES_STD_COLOR)
225 1.3.12.2 yamt printf("\tStandard color space\n");
226 1.3.12.2 yamt if (edid->edid_features & EDID_FEATURES_PREFERRED_TIMING)
227 1.3.12.2 yamt printf("\tPreferred timing\n");
228 1.3.12.2 yamt if (edid->edid_features & EDID_FEATURES_DEFAULT_GTF)
229 1.3.12.2 yamt printf("\tDefault GTF supported\n");
230 1.3.12.2 yamt
231 1.3.12.2 yamt printf("Chroma Info:\n");
232 1.3.12.2 yamt printf("\tRed X: 0.%03d\n", edid->edid_chroma.ec_redx);
233 1.3.12.2 yamt printf("\tRed Y: 0.%03d\n", edid->edid_chroma.ec_redy);
234 1.3.12.2 yamt printf("\tGrn X: 0.%03d\n", edid->edid_chroma.ec_greenx);
235 1.3.12.2 yamt printf("\tGrn Y: 0.%03d\n", edid->edid_chroma.ec_greeny);
236 1.3.12.2 yamt printf("\tBlu X: 0.%03d\n", edid->edid_chroma.ec_bluex);
237 1.3.12.2 yamt printf("\tBlu Y: 0.%03d\n", edid->edid_chroma.ec_bluey);
238 1.3.12.2 yamt printf("\tWht X: 0.%03d\n", edid->edid_chroma.ec_whitex);
239 1.3.12.2 yamt printf("\tWht Y: 0.%03d\n", edid->edid_chroma.ec_whitey);
240 1.3.12.2 yamt
241 1.3.12.2 yamt if (edid->edid_have_range) {
242 1.3.12.2 yamt printf("Range:\n");
243 1.3.12.2 yamt printf("\tHorizontal: %d - %d kHz\n",
244 1.3.12.2 yamt edid->edid_range.er_min_hfreq,
245 1.3.12.2 yamt edid->edid_range.er_max_hfreq);
246 1.3.12.2 yamt printf("\tVertical: %d - %d Hz\n",
247 1.3.12.2 yamt edid->edid_range.er_min_vfreq,
248 1.3.12.2 yamt edid->edid_range.er_max_vfreq);
249 1.3.12.2 yamt printf("\tMax Dot Clock: %d MHz\n",
250 1.3.12.2 yamt edid->edid_range.er_max_clock);
251 1.3.12.2 yamt if (edid->edid_range.er_have_gtf2) {
252 1.3.12.2 yamt printf("\tGTF2 hfreq: %d\n",
253 1.3.12.2 yamt edid->edid_range.er_gtf2_hfreq);
254 1.3.12.2 yamt printf("\tGTF2 C: %d\n", edid->edid_range.er_gtf2_c);
255 1.3.12.2 yamt printf("\tGTF2 M: %d\n", edid->edid_range.er_gtf2_m);
256 1.3.12.2 yamt printf("\tGTF2 J: %d\n", edid->edid_range.er_gtf2_j);
257 1.3.12.2 yamt printf("\tGTF2 K: %d\n", edid->edid_range.er_gtf2_k);
258 1.3.12.2 yamt }
259 1.3.12.2 yamt }
260 1.3.12.2 yamt printf("Video modes:\n");
261 1.3.12.2 yamt for (i = 0; i < edid->edid_nmodes; i++) {
262 1.3.12.2 yamt printf("\t%dx%d @ %dHz\n",
263 1.3.12.2 yamt edid->edid_modes[i].hdisplay,
264 1.3.12.2 yamt edid->edid_modes[i].vdisplay,
265 1.3.12.2 yamt DIVIDE(DIVIDE(edid->edid_modes[i].dot_clock * 1000,
266 1.3.12.2 yamt edid->edid_modes[i].htotal),
267 1.3.12.2 yamt edid->edid_modes[i].vtotal));
268 1.3.12.2 yamt }
269 1.3.12.2 yamt if (edid->edid_preferred_mode)
270 1.3.12.2 yamt printf("Preferred mode: %dx%d @ %dHz\n",
271 1.3.12.2 yamt edid->edid_preferred_mode->hdisplay,
272 1.3.12.2 yamt edid->edid_preferred_mode->vdisplay,
273 1.3.12.2 yamt DIVIDE(DIVIDE(edid->edid_preferred_mode->dot_clock * 1000,
274 1.3.12.2 yamt edid->edid_preferred_mode->htotal),
275 1.3.12.2 yamt edid->edid_preferred_mode->vtotal));
276 1.3.12.2 yamt }
277 1.3.12.2 yamt
278 1.3.12.2 yamt static const struct videomode *
279 1.3.12.2 yamt edid_mode_lookup_list(const char *name)
280 1.3.12.2 yamt {
281 1.3.12.2 yamt int i;
282 1.3.12.2 yamt
283 1.3.12.2 yamt for (i = 0; i < videomode_count; i++)
284 1.3.12.2 yamt if (strcmp(name, videomode_list[i].name) == 0)
285 1.3.12.2 yamt return &videomode_list[i];
286 1.3.12.2 yamt return NULL;
287 1.3.12.2 yamt }
288 1.3.12.2 yamt
289 1.3.12.2 yamt static int
290 1.3.12.2 yamt edid_std_timing(uint8_t *data, struct videomode *vmp)
291 1.3.12.2 yamt {
292 1.3.12.2 yamt unsigned x, y, f;
293 1.3.12.2 yamt const struct videomode *lookup;
294 1.3.12.2 yamt char name[80];
295 1.3.12.2 yamt
296 1.3.12.2 yamt if ((data[0] == 1 && data[1] == 1) ||
297 1.3.12.2 yamt (data[0] == 0 && data[1] == 0) ||
298 1.3.12.2 yamt (data[0] == 0x20 && data[1] == 0x20))
299 1.3.12.2 yamt return 0;
300 1.3.12.2 yamt
301 1.3.12.2 yamt x = EDID_STD_TIMING_HRES(data);
302 1.3.12.2 yamt switch (EDID_STD_TIMING_RATIO(data)) {
303 1.3.12.2 yamt case EDID_STD_TIMING_RATIO_16_10:
304 1.3.12.2 yamt y = x * 10 / 16;
305 1.3.12.2 yamt break;
306 1.3.12.2 yamt case EDID_STD_TIMING_RATIO_4_3:
307 1.3.12.2 yamt y = x * 3 / 4;
308 1.3.12.2 yamt break;
309 1.3.12.2 yamt case EDID_STD_TIMING_RATIO_5_4:
310 1.3.12.2 yamt y = x * 4 / 5;
311 1.3.12.2 yamt break;
312 1.3.12.2 yamt case EDID_STD_TIMING_RATIO_16_9:
313 1.3.12.2 yamt default:
314 1.3.12.2 yamt y = x * 9 / 16;
315 1.3.12.2 yamt break;
316 1.3.12.2 yamt }
317 1.3.12.2 yamt f = EDID_STD_TIMING_VFREQ(data);
318 1.3.12.2 yamt
319 1.3.12.2 yamt /* first try to lookup the mode as a DMT timing */
320 1.3.12.2 yamt snprintf(name, sizeof (name), "%dx%dx%d", x, y, f);
321 1.3.12.2 yamt if ((lookup = edid_mode_lookup_list(name)) != NULL) {
322 1.3.12.2 yamt *vmp = *lookup;
323 1.3.12.2 yamt }
324 1.3.12.2 yamt
325 1.3.12.2 yamt /* failing that, calculate it using gtf */
326 1.3.12.2 yamt else {
327 1.3.12.2 yamt /*
328 1.3.12.2 yamt * Hmm. I'm not using alternate GTF timings, which
329 1.3.12.2 yamt * could, in theory, be present.
330 1.3.12.2 yamt */
331 1.3.12.2 yamt vesagtf_mode(x, y, f, vmp);
332 1.3.12.2 yamt }
333 1.3.12.2 yamt return 1;
334 1.3.12.2 yamt }
335 1.3.12.2 yamt
336 1.3.12.2 yamt static int
337 1.3.12.2 yamt edid_det_timing(uint8_t *data, struct videomode *vmp)
338 1.3.12.2 yamt {
339 1.3.12.2 yamt unsigned hactive, hblank, hsyncwid, hsyncoff;
340 1.3.12.2 yamt unsigned vactive, vblank, vsyncwid, vsyncoff;
341 1.3.12.2 yamt uint8_t flags;
342 1.3.12.2 yamt
343 1.3.12.2 yamt flags = EDID_DET_TIMING_FLAGS(data);
344 1.3.12.2 yamt
345 1.3.12.2 yamt /* we don't support stereo modes (for now) */
346 1.3.12.2 yamt if (flags & (EDID_DET_TIMING_FLAG_STEREO |
347 1.3.12.2 yamt EDID_DET_TIMING_FLAG_STEREO1))
348 1.3.12.2 yamt return 0;
349 1.3.12.2 yamt
350 1.3.12.2 yamt vmp->dot_clock = EDID_DET_TIMING_DOT_CLOCK(data) / 1000;
351 1.3.12.2 yamt
352 1.3.12.2 yamt hactive = EDID_DET_TIMING_HACTIVE(data);
353 1.3.12.2 yamt hblank = EDID_DET_TIMING_HBLANK(data);
354 1.3.12.2 yamt hsyncwid = EDID_DET_TIMING_HSYNC_WIDTH(data);
355 1.3.12.2 yamt hsyncoff = EDID_DET_TIMING_HSYNC_OFFSET(data);
356 1.3.12.2 yamt
357 1.3.12.2 yamt vactive = EDID_DET_TIMING_VACTIVE(data);
358 1.3.12.2 yamt vblank = EDID_DET_TIMING_VBLANK(data);
359 1.3.12.2 yamt vsyncwid = EDID_DET_TIMING_VSYNC_WIDTH(data);
360 1.3.12.2 yamt vsyncoff = EDID_DET_TIMING_VSYNC_OFFSET(data);
361 1.3.12.2 yamt
362 1.3.12.2 yamt /* XXX: I'm not doing anything with the borders, should I? */
363 1.3.12.2 yamt
364 1.3.12.2 yamt vmp->hdisplay = hactive;
365 1.3.12.2 yamt vmp->htotal = hactive + hblank;
366 1.3.12.2 yamt vmp->hsync_start = hactive + hsyncoff;
367 1.3.12.2 yamt vmp->hsync_end = vmp->hsync_start + hsyncwid;
368 1.3.12.2 yamt
369 1.3.12.2 yamt vmp->vdisplay = vactive;
370 1.3.12.2 yamt vmp->vtotal = vactive + vblank;
371 1.3.12.2 yamt vmp->vsync_start = vactive + vsyncoff;
372 1.3.12.2 yamt vmp->vsync_end = vmp->vsync_start + vsyncwid;
373 1.3.12.2 yamt
374 1.3.12.2 yamt vmp->flags = 0;
375 1.3.12.2 yamt
376 1.3.12.2 yamt if (flags & EDID_DET_TIMING_FLAG_INTERLACE)
377 1.3.12.2 yamt vmp->flags |= VID_INTERLACE;
378 1.3.12.2 yamt if (flags & EDID_DET_TIMING_FLAG_HSYNC_POSITIVE)
379 1.3.12.2 yamt vmp->flags |= VID_PHSYNC;
380 1.3.12.2 yamt else
381 1.3.12.2 yamt vmp->flags |= VID_NHSYNC;
382 1.3.12.2 yamt
383 1.3.12.2 yamt if (flags & EDID_DET_TIMING_FLAG_VSYNC_POSITIVE)
384 1.3.12.2 yamt vmp->flags |= VID_PVSYNC;
385 1.3.12.2 yamt else
386 1.3.12.2 yamt vmp->flags |= VID_NVSYNC;
387 1.3.12.2 yamt
388 1.3.12.2 yamt return 1;
389 1.3.12.2 yamt }
390 1.3.12.2 yamt
391 1.3.12.2 yamt static void
392 1.3.12.2 yamt edid_block(struct edid_info *edid, uint8_t *data)
393 1.3.12.2 yamt {
394 1.3.12.2 yamt int i;
395 1.3.12.2 yamt struct videomode mode;
396 1.3.12.2 yamt
397 1.3.12.2 yamt if (EDID_BLOCK_IS_DET_TIMING(data)) {
398 1.3.12.2 yamt if (edid_det_timing(data, &mode)) {
399 1.3.12.2 yamt edid->edid_modes[edid->edid_nmodes] = mode;
400 1.3.12.2 yamt if (edid->edid_preferred_mode == NULL) {
401 1.3.12.2 yamt edid->edid_preferred_mode =
402 1.3.12.2 yamt &edid->edid_modes[edid->edid_nmodes];
403 1.3.12.2 yamt }
404 1.3.12.2 yamt edid->edid_nmodes++;
405 1.3.12.2 yamt }
406 1.3.12.2 yamt return;
407 1.3.12.2 yamt }
408 1.3.12.2 yamt
409 1.3.12.2 yamt switch (EDID_BLOCK_TYPE(data)) {
410 1.3.12.2 yamt case EDID_DESC_BLOCK_TYPE_SERIAL:
411 1.3.12.2 yamt memcpy(edid->edid_serial,
412 1.3.12.2 yamt data + EDID_DESC_ASCII_DATA_OFFSET,
413 1.3.12.2 yamt EDID_DESC_ASCII_DATA_LEN);
414 1.3.12.2 yamt edid->edid_serial[sizeof (edid->edid_serial) - 1] = 0;
415 1.3.12.2 yamt break;
416 1.3.12.2 yamt
417 1.3.12.2 yamt case EDID_DESC_BLOCK_TYPE_ASCII:
418 1.3.12.2 yamt memcpy(edid->edid_comment,
419 1.3.12.2 yamt data + EDID_DESC_ASCII_DATA_OFFSET,
420 1.3.12.2 yamt EDID_DESC_ASCII_DATA_LEN);
421 1.3.12.2 yamt edid->edid_comment[sizeof (edid->edid_comment) - 1] = 0;
422 1.3.12.2 yamt break;
423 1.3.12.2 yamt
424 1.3.12.2 yamt case EDID_DESC_BLOCK_TYPE_RANGE:
425 1.3.12.2 yamt edid->edid_have_range = 1;
426 1.3.12.2 yamt edid->edid_range.er_min_vfreq =
427 1.3.12.2 yamt EDID_DESC_RANGE_MIN_VFREQ(data);
428 1.3.12.2 yamt edid->edid_range.er_max_vfreq =
429 1.3.12.2 yamt EDID_DESC_RANGE_MAX_VFREQ(data);
430 1.3.12.2 yamt edid->edid_range.er_min_hfreq =
431 1.3.12.2 yamt EDID_DESC_RANGE_MIN_HFREQ(data);
432 1.3.12.2 yamt edid->edid_range.er_max_hfreq =
433 1.3.12.2 yamt EDID_DESC_RANGE_MAX_HFREQ(data);
434 1.3.12.2 yamt edid->edid_range.er_max_clock =
435 1.3.12.2 yamt EDID_DESC_RANGE_MAX_CLOCK(data);
436 1.3.12.2 yamt if (EDID_DESC_RANGE_HAVE_GTF2(data)) {
437 1.3.12.2 yamt edid->edid_range.er_have_gtf2 = 1;
438 1.3.12.2 yamt edid->edid_range.er_gtf2_hfreq =
439 1.3.12.2 yamt EDID_DESC_RANGE_GTF2_HFREQ(data);
440 1.3.12.2 yamt edid->edid_range.er_gtf2_c =
441 1.3.12.2 yamt EDID_DESC_RANGE_GTF2_C(data);
442 1.3.12.2 yamt edid->edid_range.er_gtf2_m =
443 1.3.12.2 yamt EDID_DESC_RANGE_GTF2_M(data);
444 1.3.12.2 yamt edid->edid_range.er_gtf2_j =
445 1.3.12.2 yamt EDID_DESC_RANGE_GTF2_J(data);
446 1.3.12.2 yamt edid->edid_range.er_gtf2_k =
447 1.3.12.2 yamt EDID_DESC_RANGE_GTF2_K(data);
448 1.3.12.2 yamt }
449 1.3.12.2 yamt break;
450 1.3.12.2 yamt
451 1.3.12.2 yamt case EDID_DESC_BLOCK_TYPE_NAME:
452 1.3.12.2 yamt /* copy the product name into place */
453 1.3.12.2 yamt memcpy(edid->edid_productname,
454 1.3.12.2 yamt data + EDID_DESC_ASCII_DATA_OFFSET,
455 1.3.12.2 yamt EDID_DESC_ASCII_DATA_LEN);
456 1.3.12.2 yamt break;
457 1.3.12.2 yamt
458 1.3.12.2 yamt case EDID_DESC_BLOCK_TYPE_STD_TIMING:
459 1.3.12.2 yamt data += EDID_DESC_STD_TIMING_START;
460 1.3.12.2 yamt for (i = 0; i < EDID_DESC_STD_TIMING_COUNT; i++) {
461 1.3.12.2 yamt if (edid_std_timing(data, &mode)) {
462 1.3.12.2 yamt edid->edid_modes[edid->edid_nmodes] = mode;
463 1.3.12.2 yamt edid->edid_nmodes++;
464 1.3.12.2 yamt }
465 1.3.12.2 yamt data += 2;
466 1.3.12.2 yamt }
467 1.3.12.2 yamt break;
468 1.3.12.2 yamt
469 1.3.12.2 yamt case EDID_DESC_BLOCK_TYPE_COLOR_POINT:
470 1.3.12.2 yamt /* XXX: not implemented yet */
471 1.3.12.2 yamt break;
472 1.3.12.2 yamt }
473 1.3.12.2 yamt }
474 1.3.12.2 yamt
475 1.3.12.2 yamt /*
476 1.3.12.2 yamt * Gets EDID version in BCD, e.g. EDID v1.3 returned as 0x0103
477 1.3.12.2 yamt */
478 1.3.12.2 yamt int
479 1.3.12.2 yamt edid_parse(uint8_t *data, struct edid_info *edid)
480 1.3.12.2 yamt {
481 1.3.12.2 yamt uint16_t manfid, estmodes;
482 1.3.12.2 yamt const struct videomode *vmp;
483 1.3.12.2 yamt int i;
484 1.3.12.2 yamt const char *name;
485 1.3.12.3 yamt int max_dotclock = 0;
486 1.3.12.3 yamt int mhz;
487 1.3.12.2 yamt
488 1.3.12.2 yamt if (edid_is_valid(data) != 0)
489 1.3.12.2 yamt return -1;
490 1.3.12.2 yamt
491 1.3.12.2 yamt /* get product identification */
492 1.3.12.2 yamt manfid = EDID_VENDOR_ID(data);
493 1.3.12.2 yamt edid->edid_vendor[0] = EDID_MANFID_0(manfid);
494 1.3.12.2 yamt edid->edid_vendor[1] = EDID_MANFID_1(manfid);
495 1.3.12.2 yamt edid->edid_vendor[2] = EDID_MANFID_2(manfid);
496 1.3.12.2 yamt edid->edid_vendor[3] = 0; /* null terminate for convenience */
497 1.3.12.2 yamt
498 1.3.12.2 yamt edid->edid_product = data[EDID_OFFSET_PRODUCT_ID] +
499 1.3.12.2 yamt (data[EDID_OFFSET_PRODUCT_ID + 1] << 8);
500 1.3.12.2 yamt
501 1.3.12.2 yamt name = edid_findvendor(edid->edid_vendor);
502 1.3.12.2 yamt if (name != NULL) {
503 1.3.12.2 yamt snprintf(edid->edid_vendorname,
504 1.3.12.2 yamt sizeof (edid->edid_vendorname), "%s", name);
505 1.3.12.2 yamt }
506 1.3.12.2 yamt edid->edid_vendorname[sizeof (edid->edid_vendorname) - 1] = 0;
507 1.3.12.2 yamt
508 1.3.12.2 yamt name = edid_findproduct(edid->edid_vendor, edid->edid_product);
509 1.3.12.2 yamt if (name != NULL) {
510 1.3.12.2 yamt snprintf(edid->edid_productname,
511 1.3.12.2 yamt sizeof (edid->edid_productname), "%s", name);
512 1.3.12.2 yamt }
513 1.3.12.2 yamt edid->edid_productname[sizeof (edid->edid_productname) - 1] = 0;
514 1.3.12.2 yamt
515 1.3.12.2 yamt snprintf(edid->edid_serial, sizeof (edid->edid_serial), "%08x",
516 1.3.12.2 yamt EDID_SERIAL_NUMBER(data));
517 1.3.12.2 yamt
518 1.3.12.2 yamt edid->edid_week = EDID_WEEK(data);
519 1.3.12.2 yamt edid->edid_year = EDID_YEAR(data);
520 1.3.12.2 yamt
521 1.3.12.2 yamt /* get edid revision */
522 1.3.12.2 yamt edid->edid_version = EDID_VERSION(data);
523 1.3.12.2 yamt edid->edid_revision = EDID_REVISION(data);
524 1.3.12.2 yamt
525 1.3.12.2 yamt edid->edid_video_input = EDID_VIDEO_INPUT(data);
526 1.3.12.2 yamt edid->edid_max_hsize = EDID_MAX_HSIZE(data);
527 1.3.12.2 yamt edid->edid_max_vsize = EDID_MAX_VSIZE(data);
528 1.3.12.2 yamt
529 1.3.12.2 yamt edid->edid_gamma = EDID_GAMMA(data);
530 1.3.12.2 yamt edid->edid_features = EDID_FEATURES(data);
531 1.3.12.2 yamt
532 1.3.12.2 yamt edid->edid_chroma.ec_redx = EDID_CHROMA_REDX(data);
533 1.3.12.2 yamt edid->edid_chroma.ec_redy = EDID_CHROMA_REDX(data);
534 1.3.12.2 yamt edid->edid_chroma.ec_greenx = EDID_CHROMA_GREENX(data);
535 1.3.12.2 yamt edid->edid_chroma.ec_greeny = EDID_CHROMA_GREENY(data);
536 1.3.12.2 yamt edid->edid_chroma.ec_bluex = EDID_CHROMA_BLUEX(data);
537 1.3.12.2 yamt edid->edid_chroma.ec_bluey = EDID_CHROMA_BLUEY(data);
538 1.3.12.2 yamt edid->edid_chroma.ec_whitex = EDID_CHROMA_WHITEX(data);
539 1.3.12.2 yamt edid->edid_chroma.ec_whitey = EDID_CHROMA_WHITEY(data);
540 1.3.12.2 yamt
541 1.3.12.2 yamt /* lookup established modes */
542 1.3.12.3 yamt edid->edid_nmodes = 0;
543 1.3.12.3 yamt edid->edid_preferred_mode = NULL;
544 1.3.12.2 yamt estmodes = EDID_EST_TIMING(data);
545 1.3.12.2 yamt for (i = 0; i < 16; i++) {
546 1.3.12.2 yamt if (estmodes & (1 << i)) {
547 1.3.12.2 yamt vmp = edid_mode_lookup_list(_edid_modes[i]);
548 1.3.12.2 yamt if (vmp != NULL) {
549 1.3.12.2 yamt edid->edid_modes[edid->edid_nmodes] = *vmp;
550 1.3.12.2 yamt edid->edid_nmodes++;
551 1.3.12.2 yamt }
552 1.3.12.3 yamt #ifdef DIAGNOSTIC
553 1.3.12.3 yamt else
554 1.3.12.3 yamt printf("no data for est. mode %s\n",
555 1.3.12.3 yamt _edid_modes[i]);
556 1.3.12.3 yamt #endif
557 1.3.12.2 yamt }
558 1.3.12.2 yamt }
559 1.3.12.2 yamt
560 1.3.12.2 yamt /* do standard timing section */
561 1.3.12.2 yamt for (i = 0; i < EDID_STD_TIMING_COUNT; i++) {
562 1.3.12.2 yamt struct videomode mode;
563 1.3.12.2 yamt if (edid_std_timing(data + EDID_OFFSET_STD_TIMING + i * 2,
564 1.3.12.2 yamt &mode)) {
565 1.3.12.2 yamt edid->edid_modes[edid->edid_nmodes] = mode;
566 1.3.12.2 yamt edid->edid_nmodes++;
567 1.3.12.2 yamt }
568 1.3.12.2 yamt }
569 1.3.12.2 yamt
570 1.3.12.2 yamt /* do detailed timings and descriptors */
571 1.3.12.2 yamt for (i = 0; i < EDID_BLOCK_COUNT; i++) {
572 1.3.12.2 yamt edid_block(edid, data + EDID_OFFSET_DESC_BLOCK +
573 1.3.12.2 yamt i * EDID_BLOCK_SIZE);
574 1.3.12.2 yamt }
575 1.3.12.2 yamt
576 1.3.12.2 yamt edid_strchomp(edid->edid_vendorname);
577 1.3.12.2 yamt edid_strchomp(edid->edid_productname);
578 1.3.12.2 yamt edid_strchomp(edid->edid_serial);
579 1.3.12.2 yamt edid_strchomp(edid->edid_comment);
580 1.3.12.2 yamt
581 1.3.12.3 yamt /*
582 1.3.12.3 yamt * XXX
583 1.3.12.3 yamt * some monitors lie about their maximum supported dot clock
584 1.3.12.3 yamt * by claiming to support modes which need a higher dot clock
585 1.3.12.3 yamt * than the stated maximum.
586 1.3.12.3 yamt * For sanity's sake we bump it to the highest dot clock we find
587 1.3.12.3 yamt * in the list of supported modes
588 1.3.12.3 yamt */
589 1.3.12.3 yamt for (i = 0; i < edid->edid_nmodes; i++)
590 1.3.12.3 yamt if (edid->edid_modes[i].dot_clock > max_dotclock)
591 1.3.12.3 yamt max_dotclock = edid->edid_modes[i].dot_clock;
592 1.3.12.3 yamt
593 1.3.12.3 yamt aprint_verbose("max_dotclock according to supported modes: %d\n",
594 1.3.12.3 yamt max_dotclock);
595 1.3.12.3 yamt
596 1.3.12.3 yamt mhz = (max_dotclock + 999) / 1000;
597 1.3.12.3 yamt
598 1.3.12.3 yamt if (edid->edid_have_range) {
599 1.3.12.3 yamt
600 1.3.12.3 yamt if (mhz > edid->edid_range.er_max_clock)
601 1.3.12.3 yamt edid->edid_range.er_max_clock = mhz;
602 1.3.12.3 yamt } else
603 1.3.12.3 yamt edid->edid_range.er_max_clock = mhz;
604 1.3.12.3 yamt
605 1.3.12.2 yamt return 0;
606 1.3.12.2 yamt }
607 1.3.12.2 yamt
608