Imported Upstream version 1.15.1
[deb_xorg-server.git] / hw / xfree86 / ddc / print_edid.c
CommitLineData
a09e091a
JB
1/*
2 * Copyright 1998 by Egbert Eich <Egbert.Eich@Physik.TU-Darmstadt.DE>
3 * Copyright 2007 Red Hat, Inc.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * print_edid.c: print out all information retrieved from display device
25 */
26
27#ifdef HAVE_XORG_CONFIG_H
28#include <xorg-config.h>
29#endif
30
31/* XXX kinda gross */
32#define _PARSE_EDID_
33
34#include "misc.h"
35#include "xf86.h"
36#include "xf86_OSproc.h"
37#include "xf86DDC.h"
38#include "edid.h"
39
40#define EDID_WIDTH 16
41
42static void
43print_vendor(int scrnIndex, struct vendor *c)
44{
45 xf86DrvMsg(scrnIndex, X_INFO, "Manufacturer: %s Model: %x Serial#: %u\n",
46 (char *) &c->name, c->prod_id, c->serial);
47 xf86DrvMsg(scrnIndex, X_INFO, "Year: %u Week: %u\n", c->year, c->week);
48}
49
50static void
51print_version(int scrnIndex, struct edid_version *c)
52{
53 xf86DrvMsg(scrnIndex, X_INFO, "EDID Version: %u.%u\n", c->version,
54 c->revision);
55}
56
57static const char *digital_interfaces[] = {
58 "undefined",
59 "DVI",
60 "HDMI-a",
61 "HDMI-b",
62 "MDDI",
63 "DisplayPort",
64 "unknown"
65};
66
67static void
68print_input_features(int scrnIndex, struct disp_features *c,
69 struct edid_version *v)
70{
71 if (DIGITAL(c->input_type)) {
72 xf86DrvMsg(scrnIndex, X_INFO, "Digital Display Input\n");
73 if (v->revision == 2 || v->revision == 3) {
74 if (DFP1(c->input_dfp))
75 xf86DrvMsg(scrnIndex, X_INFO, "DFP 1.x compatible TMDS\n");
76 }
77 else if (v->revision >= 4) {
78 int interface = c->input_interface;
79 int bpc = c->input_bpc;
80
81 if (interface > 6)
82 interface = 6; /* unknown */
83 if (bpc == 0 || bpc == 7)
84 xf86DrvMsg(scrnIndex, X_INFO, "Undefined color depth\n");
85 else
86 xf86DrvMsg(scrnIndex, X_INFO, "%d bits per channel\n",
87 bpc * 2 + 4);
88 xf86DrvMsg(scrnIndex, X_INFO, "Digital interface is %s\n",
89 digital_interfaces[interface]);
90 }
91 }
92 else {
93 xf86DrvMsg(scrnIndex, X_INFO, "Analog Display Input, ");
94 xf86ErrorF("Input Voltage Level: ");
95 switch (c->input_voltage) {
96 case V070:
97 xf86ErrorF("0.700/0.300 V\n");
98 break;
99 case V071:
100 xf86ErrorF("0.714/0.286 V\n");
101 break;
102 case V100:
103 xf86ErrorF("1.000/0.400 V\n");
104 break;
105 case V007:
106 xf86ErrorF("0.700/0.700 V\n");
107 break;
108 default:
109 xf86ErrorF("undefined\n");
110 }
111 if (SIG_SETUP(c->input_setup))
112 xf86DrvMsg(scrnIndex, X_INFO, "Signal levels configurable\n");
113 xf86DrvMsg(scrnIndex, X_INFO, "Sync:");
114 if (SEP_SYNC(c->input_sync))
115 xf86ErrorF(" Separate");
116 if (COMP_SYNC(c->input_sync))
117 xf86ErrorF(" Composite");
118 if (SYNC_O_GREEN(c->input_sync))
119 xf86ErrorF(" SyncOnGreen");
120 if (SYNC_SERR(c->input_sync))
121 xf86ErrorF("Serration on. "
122 "V.Sync Pulse req. if CompSync or SyncOnGreen\n");
123 else
124 xf86ErrorF("\n");
125 }
126}
127
128static void
129print_dpms_features(int scrnIndex, struct disp_features *c,
130 struct edid_version *v)
131{
132 if (c->dpms) {
133 xf86DrvMsg(scrnIndex, X_INFO, "DPMS capabilities:");
134 if (DPMS_STANDBY(c->dpms))
135 xf86ErrorF(" StandBy");
136 if (DPMS_SUSPEND(c->dpms))
137 xf86ErrorF(" Suspend");
138 if (DPMS_OFF(c->dpms))
139 xf86ErrorF(" Off");
140 }
141 else
142 xf86DrvMsg(scrnIndex, X_INFO, "No DPMS capabilities specified");
143 if (!c->input_type) { /* analog */
144 switch (c->display_type) {
145 case DISP_MONO:
146 xf86ErrorF("; Monochorome/GrayScale Display\n");
147 break;
148 case DISP_RGB:
149 xf86ErrorF("; RGB/Color Display\n");
150 break;
151 case DISP_MULTCOLOR:
152 xf86ErrorF("; Non RGB Multicolor Display\n");
153 break;
154 default:
155 xf86ErrorF("\n");
156 break;
157 }
158 }
159 else {
160 int enc = c->display_type;
161
162 xf86ErrorF("\n");
163 xf86DrvMsg(scrnIndex, X_INFO, "Supported color encodings: "
164 "RGB 4:4:4 %s%s\n",
165 enc & DISP_YCRCB444 ? "YCrCb 4:4:4 " : "",
166 enc & DISP_YCRCB422 ? "YCrCb 4:2:2" : "");
167 }
168
169 if (STD_COLOR_SPACE(c->msc))
170 xf86DrvMsg(scrnIndex, X_INFO,
171 "Default color space is primary color space\n");
172
173 if (PREFERRED_TIMING_MODE(c->msc) || v->revision >= 4) {
174 xf86DrvMsg(scrnIndex, X_INFO,
175 "First detailed timing is preferred mode\n");
176 if (v->revision >= 4)
177 xf86DrvMsg(scrnIndex, X_INFO,
178 "Preferred mode is native pixel format and refresh rate\n");
179 }
180 else if (v->revision == 3) {
181 xf86DrvMsg(scrnIndex, X_INFO,
182 "First detailed timing not preferred "
183 "mode in violation of standard!\n");
184 }
185
186 if (v->revision >= 4) {
187 if (GFT_SUPPORTED(c->msc)) {
188 xf86DrvMsg(scrnIndex, X_INFO, "Display is continuous-frequency\n");
189 }
190 }
191 else {
192 if (GFT_SUPPORTED(c->msc))
193 xf86DrvMsg(scrnIndex, X_INFO, "GTF timings supported\n");
194 }
195}
196
197static void
198print_whitepoint(int scrnIndex, struct disp_features *disp)
199{
200 xf86DrvMsg(scrnIndex, X_INFO, "redX: %.3f redY: %.3f ",
201 disp->redx, disp->redy);
202 xf86ErrorF("greenX: %.3f greenY: %.3f\n", disp->greenx, disp->greeny);
203 xf86DrvMsg(scrnIndex, X_INFO, "blueX: %.3f blueY: %.3f ",
204 disp->bluex, disp->bluey);
205 xf86ErrorF("whiteX: %.3f whiteY: %.3f\n", disp->whitex, disp->whitey);
206}
207
208static void
209print_display(int scrnIndex, struct disp_features *disp, struct edid_version *v)
210{
211 print_input_features(scrnIndex, disp, v);
212 if (disp->hsize && disp->vsize) {
213 xf86DrvMsg(scrnIndex, X_INFO, "Max Image Size [cm]: ");
214 xf86ErrorF("horiz.: %i ", disp->hsize);
215 xf86ErrorF("vert.: %i\n", disp->vsize);
216 }
217 else if (v->revision >= 4 && (disp->hsize || disp->vsize)) {
218 if (disp->hsize)
219 xf86DrvMsg(scrnIndex, X_INFO, "Aspect ratio: %.2f (landscape)\n",
220 (disp->hsize + 99) / 100.0);
221 if (disp->vsize)
222 xf86DrvMsg(scrnIndex, X_INFO, "Aspect ratio: %.2f (portrait)\n",
223 100.0 / (float) (disp->vsize + 99));
224
225 }
226 else {
227 xf86DrvMsg(scrnIndex, X_INFO, "Indeterminate output size\n");
228 }
229
230 if (!disp->gamma && v->revision >= 1.4)
231 xf86DrvMsg(scrnIndex, X_INFO, "Gamma defined in extension block\n");
232 else
233 xf86DrvMsg(scrnIndex, X_INFO, "Gamma: %.2f\n", disp->gamma);
234
235 print_dpms_features(scrnIndex, disp, v);
236 print_whitepoint(scrnIndex, disp);
237}
238
239static void
240print_established_timings(int scrnIndex, struct established_timings *t)
241{
242 unsigned char c;
243
244 if (t->t1 || t->t2 || t->t_manu)
245 xf86DrvMsg(scrnIndex, X_INFO, "Supported established timings:\n");
246 c = t->t1;
247 if (c & 0x80)
248 xf86DrvMsg(scrnIndex, X_INFO, "720x400@70Hz\n");
249 if (c & 0x40)
250 xf86DrvMsg(scrnIndex, X_INFO, "720x400@88Hz\n");
251 if (c & 0x20)
252 xf86DrvMsg(scrnIndex, X_INFO, "640x480@60Hz\n");
253 if (c & 0x10)
254 xf86DrvMsg(scrnIndex, X_INFO, "640x480@67Hz\n");
255 if (c & 0x08)
256 xf86DrvMsg(scrnIndex, X_INFO, "640x480@72Hz\n");
257 if (c & 0x04)
258 xf86DrvMsg(scrnIndex, X_INFO, "640x480@75Hz\n");
259 if (c & 0x02)
260 xf86DrvMsg(scrnIndex, X_INFO, "800x600@56Hz\n");
261 if (c & 0x01)
262 xf86DrvMsg(scrnIndex, X_INFO, "800x600@60Hz\n");
263 c = t->t2;
264 if (c & 0x80)
265 xf86DrvMsg(scrnIndex, X_INFO, "800x600@72Hz\n");
266 if (c & 0x40)
267 xf86DrvMsg(scrnIndex, X_INFO, "800x600@75Hz\n");
268 if (c & 0x20)
269 xf86DrvMsg(scrnIndex, X_INFO, "832x624@75Hz\n");
270 if (c & 0x10)
271 xf86DrvMsg(scrnIndex, X_INFO, "1024x768@87Hz (interlaced)\n");
272 if (c & 0x08)
273 xf86DrvMsg(scrnIndex, X_INFO, "1024x768@60Hz\n");
274 if (c & 0x04)
275 xf86DrvMsg(scrnIndex, X_INFO, "1024x768@70Hz\n");
276 if (c & 0x02)
277 xf86DrvMsg(scrnIndex, X_INFO, "1024x768@75Hz\n");
278 if (c & 0x01)
279 xf86DrvMsg(scrnIndex, X_INFO, "1280x1024@75Hz\n");
280 c = t->t_manu;
281 if (c & 0x80)
282 xf86DrvMsg(scrnIndex, X_INFO, "1152x864@75Hz\n");
283 xf86DrvMsg(scrnIndex, X_INFO, "Manufacturer's mask: %X\n", c & 0x7F);
284}
285
286static void
287print_std_timings(int scrnIndex, struct std_timings *t)
288{
289 int i;
290 char done = 0;
291
292 for (i = 0; i < STD_TIMINGS; i++) {
293 if (t[i].hsize > 256) { /* sanity check */
294 if (!done) {
295 xf86DrvMsg(scrnIndex, X_INFO, "Supported standard timings:\n");
296 done = 1;
297 }
298 xf86DrvMsg(scrnIndex, X_INFO,
299 "#%i: hsize: %i vsize %i refresh: %i vid: %i\n",
300 i, t[i].hsize, t[i].vsize, t[i].refresh, t[i].id);
301 }
302 }
303}
304
305static void
306print_cvt_timings(int si, struct cvt_timings *t)
307{
308 int i;
309
310 for (i = 0; i < 4; i++) {
311 if (t[i].height) {
312 xf86DrvMsg(si, X_INFO, "%dx%d @ %s%s%s%s%s Hz\n",
313 t[i].width, t[i].height,
314 t[i].rates & 0x10 ? "50," : "",
315 t[i].rates & 0x08 ? "60," : "",
316 t[i].rates & 0x04 ? "75," : "",
317 t[i].rates & 0x02 ? "85," : "",
318 t[i].rates & 0x01 ? "60RB" : "");
319 }
320 else
321 break;
322 }
323}
324
325static void
326print_detailed_timings(int scrnIndex, struct detailed_timings *t)
327{
328
329 if (t->clock > 15000000) { /* sanity check */
330 xf86DrvMsg(scrnIndex, X_INFO, "Supported detailed timing:\n");
331 xf86DrvMsg(scrnIndex, X_INFO, "clock: %.1f MHz ",
332 t->clock / 1000000.0);
333 xf86ErrorF("Image Size: %i x %i mm\n", t->h_size, t->v_size);
334 xf86DrvMsg(scrnIndex, X_INFO,
335 "h_active: %i h_sync: %i h_sync_end %i h_blank_end %i ",
336 t->h_active, t->h_sync_off + t->h_active,
337 t->h_sync_off + t->h_sync_width + t->h_active,
338 t->h_active + t->h_blanking);
339 xf86ErrorF("h_border: %i\n", t->h_border);
340 xf86DrvMsg(scrnIndex, X_INFO,
341 "v_active: %i v_sync: %i v_sync_end %i v_blanking: %i ",
342 t->v_active, t->v_sync_off + t->v_active,
343 t->v_sync_off + t->v_sync_width + t->v_active,
344 t->v_active + t->v_blanking);
345 xf86ErrorF("v_border: %i\n", t->v_border);
346 if (IS_STEREO(t->stereo)) {
347 xf86DrvMsg(scrnIndex, X_INFO, "Stereo: ");
348 if (IS_RIGHT_STEREO(t->stereo)) {
349 if (!t->stereo_1)
350 xf86ErrorF("right channel on sync\n");
351 else
352 xf86ErrorF("left channel on sync\n");
353 }
354 else if (IS_LEFT_STEREO(t->stereo)) {
355 if (!t->stereo_1)
356 xf86ErrorF("right channel on even line\n");
357 else
358 xf86ErrorF("left channel on evel line\n");
359 }
360 if (IS_4WAY_STEREO(t->stereo)) {
361 if (!t->stereo_1)
362 xf86ErrorF("4-way interleaved\n");
363 else
364 xf86ErrorF("side-by-side interleaved");
365 }
366 }
367 }
368}
369
370/* This function handle all detailed patchs,
371 * including EDID and EDID-extension
372 */
373struct det_print_parameter {
374 xf86MonPtr m;
375 int index;
376 ddc_quirk_t quirks;
377};
378
379static void
380handle_detailed_print(struct detailed_monitor_section *det_mon, void *data)
381{
382 int j, scrnIndex;
383 struct det_print_parameter *p;
384
385 p = (struct det_print_parameter *) data;
386 scrnIndex = p->m->scrnIndex;
387 xf86DetTimingApplyQuirks(det_mon, p->quirks,
388 p->m->features.hsize, p->m->features.vsize);
389
390 switch (det_mon->type) {
391 case DT:
392 print_detailed_timings(scrnIndex, &det_mon->section.d_timings);
393 break;
394 case DS_SERIAL:
395 xf86DrvMsg(scrnIndex, X_INFO, "Serial No: %s\n",
396 det_mon->section.serial);
397 break;
398 case DS_ASCII_STR:
399 xf86DrvMsg(scrnIndex, X_INFO, " %s\n", det_mon->section.ascii_data);
400 break;
401 case DS_NAME:
402 xf86DrvMsg(scrnIndex, X_INFO, "Monitor name: %s\n",
403 det_mon->section.name);
404 break;
405 case DS_RANGES:
406 {
407 struct monitor_ranges *r = &det_mon->section.ranges;
408
409 xf86DrvMsg(scrnIndex, X_INFO,
410 "Ranges: V min: %i V max: %i Hz, H min: %i H max: %i kHz,",
411 r->min_v, r->max_v, r->min_h, r->max_h);
412 if (r->max_clock_khz != 0) {
413 xf86ErrorF(" PixClock max %i kHz\n", r->max_clock_khz);
414 if (r->maxwidth)
415 xf86DrvMsg(scrnIndex, X_INFO, "Maximum pixel width: %d\n",
416 r->maxwidth);
417 xf86DrvMsg(scrnIndex, X_INFO, "Supported aspect ratios:");
418 if (r->supported_aspect & SUPPORTED_ASPECT_4_3)
419 xf86ErrorF(" 4:3%s",
420 r->preferred_aspect ==
421 PREFERRED_ASPECT_4_3 ? "*" : "");
422 if (r->supported_aspect & SUPPORTED_ASPECT_16_9)
423 xf86ErrorF(" 16:9%s",
424 r->preferred_aspect ==
425 PREFERRED_ASPECT_16_9 ? "*" : "");
426 if (r->supported_aspect & SUPPORTED_ASPECT_16_10)
427 xf86ErrorF(" 16:10%s",
428 r->preferred_aspect ==
429 PREFERRED_ASPECT_16_10 ? "*" : "");
430 if (r->supported_aspect & SUPPORTED_ASPECT_5_4)
431 xf86ErrorF(" 5:4%s",
432 r->preferred_aspect ==
433 PREFERRED_ASPECT_5_4 ? "*" : "");
434 if (r->supported_aspect & SUPPORTED_ASPECT_15_9)
435 xf86ErrorF(" 15:9%s",
436 r->preferred_aspect ==
437 PREFERRED_ASPECT_15_9 ? "*" : "");
438 xf86ErrorF("\n");
439 xf86DrvMsg(scrnIndex, X_INFO, "Supported blankings:");
440 if (r->supported_blanking & CVT_STANDARD)
441 xf86ErrorF(" standard");
442 if (r->supported_blanking & CVT_REDUCED)
443 xf86ErrorF(" reduced");
444 xf86ErrorF("\n");
445 xf86DrvMsg(scrnIndex, X_INFO, "Supported scalings:");
446 if (r->supported_scaling & SCALING_HSHRINK)
447 xf86ErrorF(" hshrink");
448 if (r->supported_scaling & SCALING_HSTRETCH)
449 xf86ErrorF(" hstretch");
450 if (r->supported_scaling & SCALING_VSHRINK)
451 xf86ErrorF(" vshrink");
452 if (r->supported_scaling & SCALING_VSTRETCH)
453 xf86ErrorF(" vstretch");
454 xf86ErrorF("\n");
455 if (r->preferred_refresh)
456 xf86DrvMsg(scrnIndex, X_INFO, "Preferred refresh rate: %d\n",
457 r->preferred_refresh);
458 else
459 xf86DrvMsg(scrnIndex, X_INFO, "Buggy monitor, no preferred "
460 "refresh rate given\n");
461 }
462 else if (r->max_clock != 0) {
463 xf86ErrorF(" PixClock max %i MHz\n", r->max_clock);
464 }
465 else {
466 xf86ErrorF("\n");
467 }
468 if (r->gtf_2nd_f > 0)
469 xf86DrvMsg(scrnIndex, X_INFO, " 2nd GTF parameters: f: %i kHz "
470 "c: %i m: %i k %i j %i\n", r->gtf_2nd_f,
471 r->gtf_2nd_c, r->gtf_2nd_m, r->gtf_2nd_k, r->gtf_2nd_j);
472 break;
473 }
474 case DS_STD_TIMINGS:
475 for (j = 0; j < 5; j++)
476 xf86DrvMsg(scrnIndex, X_INFO,
477 "#%i: hsize: %i vsize %i refresh: %i "
478 "vid: %i\n", p->index, det_mon->section.std_t[j].hsize,
479 det_mon->section.std_t[j].vsize,
480 det_mon->section.std_t[j].refresh,
481 det_mon->section.std_t[j].id);
482 break;
483 case DS_WHITE_P:
484 for (j = 0; j < 2; j++)
485 if (det_mon->section.wp[j].index != 0)
486 xf86DrvMsg(scrnIndex, X_INFO,
487 "White point %i: whiteX: %f, whiteY: %f; gamma: %f\n",
488 det_mon->section.wp[j].index,
489 det_mon->section.wp[j].white_x,
490 det_mon->section.wp[j].white_y,
491 det_mon->section.wp[j].white_gamma);
492 break;
493 case DS_CMD:
494 xf86DrvMsg(scrnIndex, X_INFO, "Color management data: (not decoded)\n");
495 break;
496 case DS_CVT:
497 xf86DrvMsg(scrnIndex, X_INFO, "CVT 3-byte-code modes:\n");
498 print_cvt_timings(scrnIndex, det_mon->section.cvt);
499 break;
500 case DS_EST_III:
501 xf86DrvMsg(scrnIndex, X_INFO,
502 "Established timings III: (not decoded)\n");
503 break;
504 case DS_DUMMY:
505 default:
506 break;
507 }
508 if (det_mon->type >= DS_VENDOR && det_mon->type <= DS_VENDOR_MAX) {
509 xf86DrvMsg(scrnIndex, X_INFO,
510 "Unknown vendor-specific block %hx\n",
511 det_mon->type - DS_VENDOR);
512 }
513
514 p->index = p->index + 1;
515}
516
517static void
518print_number_sections(int scrnIndex, int num)
519{
520 if (num)
521 xf86DrvMsg(scrnIndex, X_INFO, "Number of EDID sections to follow: %i\n",
522 num);
523}
524
525xf86MonPtr
526xf86PrintEDID(xf86MonPtr m)
527{
528 CARD16 i, j, n;
529 char buf[EDID_WIDTH * 2 + 1];
530 struct det_print_parameter p;
531
532 if (!m)
533 return NULL;
534
535 print_vendor(m->scrnIndex, &m->vendor);
536 print_version(m->scrnIndex, &m->ver);
537 print_display(m->scrnIndex, &m->features, &m->ver);
538 print_established_timings(m->scrnIndex, &m->timings1);
539 print_std_timings(m->scrnIndex, m->timings2);
540 p.m = m;
541 p.index = 0;
542 p.quirks = xf86DDCDetectQuirks(m->scrnIndex, m, FALSE);
543 xf86ForEachDetailedBlock(m, handle_detailed_print, &p);
544 print_number_sections(m->scrnIndex, m->no_sections);
545
546 /* extension block section stuff */
547
548 xf86DrvMsg(m->scrnIndex, X_INFO, "EDID (in hex):\n");
549
550 n = 128;
551 if (m->flags & EDID_COMPLETE_RAWDATA)
552 n += m->no_sections * 128;
553
554 for (i = 0; i < n; i += j) {
555 for (j = 0; j < EDID_WIDTH; ++j) {
556 sprintf(&buf[j * 2], "%02x", m->rawData[i + j]);
557 }
558 xf86DrvMsg(m->scrnIndex, X_INFO, "\t%s\n", buf);
559 }
560
561 return m;
562}