1 /* vim: set et fde fdm=syntax ft=c.doxygen ts=4 sts=4 sw=4 : */
2 /*
3  * Copyright © 2010-2011 Saleem Abdulrasool <compnerd@compnerd.org>.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright notice,
10  *    this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright notice,
13  *    this list of conditions and the following disclaimer in the documentation
14  *    and/or other materials provided with the distribution.
15  *
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
20  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
22  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
27  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
28  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #ifndef eds_edid_h
32 #define eds_edid_h
33 
34 #define ARRAY_SIZE(arr)                         (sizeof(arr) / sizeof(arr[0]))
35 
36 #include <assert.h>
37 #include <stdint.h>
38 #include <stdbool.h>
39 
40 #define EDID_I2C_DDC_DATA_ADDRESS               (0x50)
41 
42 #define EDID_BLOCK_SIZE                         (0x80)
43 #define EDID_MAX_EXTENSIONS                     (0xfe)
44 
45 
46 static const uint8_t EDID_HEADER[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 };
47 static const uint8_t EDID_STANDARD_TIMING_DESCRIPTOR_INVALID[] = { 0x01, 0x01 };
48 
49 
50 enum edid_extension_type {
51     EDID_EXTENSION_TIMING           = 0x01, // Timing Extension
52     EDID_EXTENSION_CEA              = 0x02, // Additional Timing Block Data (CEA EDID Timing Extension)
53     EDID_EXTENSION_VTB              = 0x10, // Video Timing Block Extension (VTB-EXT)
54     EDID_EXTENSION_EDID_2_0         = 0x20, // EDID 2.0 Extension
55     EDID_EXTENSION_DI               = 0x40, // Display Information Extension (DI-EXT)
56     EDID_EXTENSION_LS               = 0x50, // Localised String Extension (LS-EXT)
57     EDID_EXTENSION_MI               = 0x60, // Microdisplay Interface Extension (MI-EXT)
58     EDID_EXTENSION_DTCDB_1          = 0xa7, // Display Transfer Characteristics Data Block (DTCDB)
59     EDID_EXTENSION_DTCDB_2          = 0xaf,
60     EDID_EXTENSION_DTCDB_3          = 0xbf,
61     EDID_EXTENSION_BLOCK_MAP        = 0xf0, // Block Map
62     EDID_EXTENSION_DDDB             = 0xff, // Display Device Data Block (DDDB)
63 };
64 
65 enum edid_display_type {
66     EDID_DISPLAY_TYPE_MONOCHROME,
67     EDID_DISPLAY_TYPE_RGB,
68     EDID_DISPLAY_TYPE_NON_RGB,
69     EDID_DISPLAY_TYPE_UNDEFINED,
70 };
71 
72 enum edid_aspect_ratio {
73     EDID_ASPECT_RATIO_16_10,
74     EDID_ASPECT_RATIO_4_3,
75     EDID_ASPECT_RATIO_5_4,
76     EDID_ASPECT_RATIO_16_9,
77 };
78 
79 enum edid_signal_sync {
80     EDID_SIGNAL_SYNC_ANALOG_COMPOSITE,
81     EDID_SIGNAL_SYNC_BIPOLAR_ANALOG_COMPOSITE,
82     EDID_SIGNAL_SYNC_DIGITAL_COMPOSITE,
83     EDID_SIGNAL_SYNC_DIGITAL_SEPARATE,
84 };
85 
86 enum edid_stereo_mode {
87     EDID_STEREO_MODE_NONE,
88     EDID_STEREO_MODE_RESERVED,
89     EDID_STEREO_MODE_FIELD_SEQUENTIAL_RIGHT,
90     EDID_STEREO_MODE_2_WAY_INTERLEAVED_RIGHT,
91     EDID_STEREO_MODE_FIELD_SEQUENTIAL_LEFT,
92     EDID_STEREO_MODE_2_WAY_INTERLEAVED_LEFT,
93     EDID_STEREO_MODE_4_WAY_INTERLEAVED,
94     EDID_STEREO_MODE_SIDE_BY_SIDE_INTERLEAVED,
95 };
96 
97 enum edid_monitor_descriptor_type {
98     EDID_MONTIOR_DESCRIPTOR_MANUFACTURER_DEFINED        = 0x0f,
99     EDID_MONITOR_DESCRIPTOR_STANDARD_TIMING_IDENTIFIERS = 0xfa,
100     EDID_MONITOR_DESCRIPTOR_COLOR_POINT                 = 0xfb,
101     EDID_MONITOR_DESCRIPTOR_MONITOR_NAME                = 0xfc,
102     EDID_MONITOR_DESCRIPTOR_MONITOR_RANGE_LIMITS        = 0xfd,
103     EDID_MONITOR_DESCRIPTOR_ASCII_STRING                = 0xfe,
104     EDID_MONITOR_DESCRIPTOR_MONITOR_SERIAL_NUMBER       = 0xff,
105 };
106 
107 enum edid_secondary_timing_support {
108     EDID_SECONDARY_TIMING_NOT_SUPPORTED,
109     EDID_SECONDARY_TIMING_GFT           = 0x02,
110 };
111 
112 
113 struct __attribute__ (( packed )) edid_detailed_timing_descriptor {
114     uint16_t pixel_clock;                               /* = value * 10000 */
115 
116     uint8_t  horizontal_active_lo;
117     uint8_t  horizontal_blanking_lo;
118 
119     unsigned horizontal_blanking_hi         : 4;
120     unsigned horizontal_active_hi           : 4;
121 
122     uint8_t  vertical_active_lo;
123     uint8_t  vertical_blanking_lo;
124 
125     unsigned vertical_blanking_hi           : 4;
126     unsigned vertical_active_hi             : 4;
127 
128     uint8_t  horizontal_sync_offset_lo;
129     uint8_t  horizontal_sync_pulse_width_lo;
130 
131     unsigned vertical_sync_pulse_width_lo   : 4;
132     unsigned vertical_sync_offset_lo        : 4;
133 
134     unsigned vertical_sync_pulse_width_hi   : 2;
135     unsigned vertical_sync_offset_hi        : 2;
136     unsigned horizontal_sync_pulse_width_hi : 2;
137     unsigned horizontal_sync_offset_hi      : 2;
138 
139     uint8_t  horizontal_image_size_lo;
140     uint8_t  vertical_image_size_lo;
141 
142     unsigned vertical_image_size_hi         : 4;
143     unsigned horizontal_image_size_hi       : 4;
144 
145     uint8_t  horizontal_border;
146     uint8_t  vertical_border;
147 
148     unsigned stereo_mode_lo                 : 1;
149     unsigned signal_pulse_polarity          : 1; /* pulse on sync, composite/horizontal polarity */
150     unsigned signal_serration_polarity      : 1; /* serrate on sync, vertical polarity */
151     unsigned signal_sync                    : 2;
152     unsigned stereo_mode_hi                 : 2;
153     unsigned interlaced                     : 1;
154 };
155 
156 static inline uint32_t
edid_detailed_timing_pixel_clock(const struct edid_detailed_timing_descriptor * const dtb)157 edid_detailed_timing_pixel_clock(const struct edid_detailed_timing_descriptor * const dtb)
158 {
159     return dtb->pixel_clock * 10000;
160 }
161 
162 static inline uint16_t
edid_detailed_timing_horizontal_blanking(const struct edid_detailed_timing_descriptor * const dtb)163 edid_detailed_timing_horizontal_blanking(const struct edid_detailed_timing_descriptor * const dtb)
164 {
165     return (dtb->horizontal_blanking_hi << 8) | dtb->horizontal_blanking_lo;
166 }
167 
168 static inline uint16_t
edid_detailed_timing_horizontal_active(const struct edid_detailed_timing_descriptor * const dtb)169 edid_detailed_timing_horizontal_active(const struct edid_detailed_timing_descriptor * const dtb)
170 {
171     return (dtb->horizontal_active_hi << 8) | dtb->horizontal_active_lo;
172 }
173 
174 static inline uint16_t
edid_detailed_timing_vertical_blanking(const struct edid_detailed_timing_descriptor * const dtb)175 edid_detailed_timing_vertical_blanking(const struct edid_detailed_timing_descriptor * const dtb)
176 {
177     return (dtb->vertical_blanking_hi << 8) | dtb->vertical_blanking_lo;
178 }
179 
180 static inline uint16_t
edid_detailed_timing_vertical_active(const struct edid_detailed_timing_descriptor * const dtb)181 edid_detailed_timing_vertical_active(const struct edid_detailed_timing_descriptor * const dtb)
182 {
183     return (dtb->vertical_active_hi << 8) | dtb->vertical_active_lo;
184 }
185 
186 static inline uint8_t
edid_detailed_timing_vertical_sync_offset(const struct edid_detailed_timing_descriptor * const dtb)187 edid_detailed_timing_vertical_sync_offset(const struct edid_detailed_timing_descriptor * const dtb)
188 {
189     return (dtb->vertical_sync_offset_hi << 4) | dtb->vertical_sync_offset_lo;
190 }
191 
192 static inline uint8_t
edid_detailed_timing_vertical_sync_pulse_width(const struct edid_detailed_timing_descriptor * const dtb)193 edid_detailed_timing_vertical_sync_pulse_width(const struct edid_detailed_timing_descriptor * const dtb)
194 {
195     return (dtb->vertical_sync_pulse_width_hi << 4) | dtb->vertical_sync_pulse_width_lo;
196 }
197 
198 static inline uint8_t
edid_detailed_timing_horizontal_sync_offset(const struct edid_detailed_timing_descriptor * const dtb)199 edid_detailed_timing_horizontal_sync_offset(const struct edid_detailed_timing_descriptor * const dtb)
200 {
201     return (dtb->horizontal_sync_offset_hi << 4) | dtb->horizontal_sync_offset_lo;
202 }
203 
204 static inline uint8_t
edid_detailed_timing_horizontal_sync_pulse_width(const struct edid_detailed_timing_descriptor * const dtb)205 edid_detailed_timing_horizontal_sync_pulse_width(const struct edid_detailed_timing_descriptor * const dtb)
206 {
207     return (dtb->horizontal_sync_pulse_width_hi << 4) | dtb->horizontal_sync_pulse_width_lo;
208 }
209 
210 static inline uint16_t
edid_detailed_timing_horizontal_image_size(const struct edid_detailed_timing_descriptor * const dtb)211 edid_detailed_timing_horizontal_image_size(const struct edid_detailed_timing_descriptor * const dtb)
212 {
213     return (dtb->horizontal_image_size_hi << 8) | dtb->horizontal_image_size_lo;
214 }
215 
216 static inline uint16_t
edid_detailed_timing_vertical_image_size(const struct edid_detailed_timing_descriptor * const dtb)217 edid_detailed_timing_vertical_image_size(const struct edid_detailed_timing_descriptor * const dtb)
218 {
219     return (dtb->vertical_image_size_hi << 8) | dtb->vertical_image_size_lo;
220 }
221 
222 static inline uint8_t
edid_detailed_timing_stereo_mode(const struct edid_detailed_timing_descriptor * const dtb)223 edid_detailed_timing_stereo_mode(const struct edid_detailed_timing_descriptor * const dtb)
224 {
225     return (dtb->stereo_mode_hi << 2 | dtb->stereo_mode_lo);
226 }
227 
228 
229 struct __attribute__ (( packed )) edid_monitor_descriptor {
230     uint16_t flag0;
231     uint8_t  flag1;
232     uint8_t  tag;
233     uint8_t  flag2;
234     uint8_t  data[13];
235 };
236 
237 typedef char edid_monitor_descriptor_string[sizeof(((struct edid_monitor_descriptor *)0)->data) + 1];
238 
239 
240 struct __attribute__ (( packed )) edid_monitor_range_limits {
241     uint8_t  minimum_vertical_rate;             /* Hz */
242     uint8_t  maximum_vertical_rate;             /* Hz */
243     uint8_t  minimum_horizontal_rate;           /* kHz */
244     uint8_t  maximum_horizontal_rate;           /* kHz */
245     uint8_t  maximum_supported_pixel_clock;     /* = (value * 10) Mhz (round to 10 MHz) */
246 
247     /* secondary timing formula */
248     uint8_t  secondary_timing_support;
249     uint8_t  reserved;
250     uint8_t  secondary_curve_start_frequency;   /* horizontal frequency / 2 kHz */
251     uint8_t  c;                                 /* = (value >> 1) */
252     uint16_t m;
253     uint8_t  k;
254     uint8_t  j;                                 /* = (value >> 1) */
255 };
256 
257 
258 struct __attribute__ (( packed )) edid_standard_timing_descriptor {
259     uint8_t  horizontal_active_pixels;         /* = (value + 31) * 8 */
260 
261     unsigned refresh_rate       : 6;           /* = value + 60 */
262     unsigned image_aspect_ratio : 2;
263 };
264 
265 uint32_t
edid_standard_timing_horizontal_active(const struct edid_standard_timing_descriptor * const desc)266 edid_standard_timing_horizontal_active(const struct edid_standard_timing_descriptor * const desc)
267 {
268     return ((desc->horizontal_active_pixels + 31) << 3);
269 }
270 
271 uint32_t
edid_standard_timing_vertical_active(const struct edid_standard_timing_descriptor * const desc)272 edid_standard_timing_vertical_active(const struct edid_standard_timing_descriptor * const desc)
273 {
274     const uint32_t hres = edid_standard_timing_horizontal_active(desc);
275 
276     switch (desc->image_aspect_ratio) {
277     case EDID_ASPECT_RATIO_16_10:
278         return ((hres * 10) >> 4);
279     case EDID_ASPECT_RATIO_4_3:
280         return ((hres * 3) >> 2);
281     case EDID_ASPECT_RATIO_5_4:
282         return ((hres << 2) / 5);
283     case EDID_ASPECT_RATIO_16_9:
284         return ((hres * 9) >> 4);
285     }
286 
287     return hres;
288 }
289 
290 uint32_t
edid_standard_timing_refresh_rate(const struct edid_standard_timing_descriptor * const desc)291 edid_standard_timing_refresh_rate(const struct edid_standard_timing_descriptor * const desc)
292 {
293     return (desc->refresh_rate + 60);
294 }
295 
296 
297 struct __attribute__ (( packed )) edid {
298     /* header information */
299     uint8_t  header[8];
300 
301     /* vendor/product identification */
302     uint16_t manufacturer;
303 
304     uint8_t  product[2];
305     uint8_t  serial_number[4];
306     uint8_t  manufacture_week;
307     uint8_t  manufacture_year;                  /* = value + 1990 */
308 
309     /* EDID version */
310     uint8_t  version;
311     uint8_t  revision;
312 
313     /* basic display parameters and features */
314     union {
315         struct __attribute__ (( packed )) {
316             unsigned dfp_1x                 : 1;    /* VESA DFP 1.x */
317             unsigned                        : 6;
318             unsigned digital                : 1;
319         } digital;
320         struct __attribute__ (( packed )) {
321             unsigned vsync_serration        : 1;
322             unsigned green_video_sync       : 1;
323             unsigned composite_sync         : 1;
324             unsigned separate_sync          : 1;
325             unsigned blank_to_black_setup   : 1;
326             unsigned signal_level_standard  : 2;
327             unsigned digital                : 1;
328         } analog;
329     } video_input_definition;
330 
331     uint8_t  maximum_horizontal_image_size;     /* cm */
332     uint8_t  maximum_vertical_image_size;       /* cm */
333 
334     uint8_t  display_transfer_characteristics;  /* gamma = (value + 100) / 100 */
335 
336     struct __attribute__ (( packed )) {
337         unsigned default_gtf                    : 1; /* generalised timing formula */
338         unsigned preferred_timing_mode          : 1;
339         unsigned standard_default_color_space   : 1;
340         unsigned display_type                   : 2;
341         unsigned active_off                     : 1;
342         unsigned suspend                        : 1;
343         unsigned standby                        : 1;
344     } feature_support;
345 
346     /* color characteristics block */
347     unsigned green_y_low    : 2;
348     unsigned green_x_low    : 2;
349     unsigned red_y_low      : 2;
350     unsigned red_x_low      : 2;
351 
352     unsigned white_y_low    : 2;
353     unsigned white_x_low    : 2;
354     unsigned blue_y_low     : 2;
355     unsigned blue_x_low     : 2;
356 
357     uint8_t  red_x;
358     uint8_t  red_y;
359     uint8_t  green_x;
360     uint8_t  green_y;
361     uint8_t  blue_x;
362     uint8_t  blue_y;
363     uint8_t  white_x;
364     uint8_t  white_y;
365 
366     /* established timings */
367     struct __attribute__ (( packed )) {
368         unsigned timing_800x600_60   : 1;
369         unsigned timing_800x600_56   : 1;
370         unsigned timing_640x480_75   : 1;
371         unsigned timing_640x480_72   : 1;
372         unsigned timing_640x480_67   : 1;
373         unsigned timing_640x480_60   : 1;
374         unsigned timing_720x400_88   : 1;
375         unsigned timing_720x400_70   : 1;
376 
377         unsigned timing_1280x1024_75 : 1;
378         unsigned timing_1024x768_75  : 1;
379         unsigned timing_1024x768_70  : 1;
380         unsigned timing_1024x768_60  : 1;
381         unsigned timing_1024x768_87  : 1;
382         unsigned timing_832x624_75   : 1;
383         unsigned timing_800x600_75   : 1;
384         unsigned timing_800x600_72   : 1;
385     } established_timings;
386 
387     struct __attribute__ (( packed )) {
388         unsigned reserved            : 7;
389         unsigned timing_1152x870_75  : 1;
390     } manufacturer_timings;
391 
392     /* standard timing id */
393     struct  edid_standard_timing_descriptor standard_timing_id[8];
394 
395     /* detailed timing */
396     union {
397         struct edid_monitor_descriptor         monitor;
398         struct edid_detailed_timing_descriptor timing;
399     } detailed_timings[4];
400 
401     uint8_t  extensions;
402     uint8_t  checksum;
403 };
404 
405 static inline void
edid_manufacturer(const struct edid * const edid,char manufacturer[4])406 edid_manufacturer(const struct edid * const edid, char manufacturer[4])
407 {
408     manufacturer[0] = '@' + ((edid->manufacturer & 0x007c) >> 2);
409     manufacturer[1] = '@' + (((edid->manufacturer & 0x0003) >> 00) << 3)
410                           | (((edid->manufacturer & 0xe000) >> 13) << 0);
411     manufacturer[2] = '@' + ((edid->manufacturer & 0x1f00) >> 8);
412     manufacturer[3] = '\0';
413 }
414 
415 static inline double
edid_gamma(const struct edid * const edid)416 edid_gamma(const struct edid * const edid)
417 {
418     return (edid->display_transfer_characteristics + 100) / 100.0;
419 }
420 
421 static inline bool
edid_detailed_timing_is_monitor_descriptor(const struct edid * const edid,const uint8_t timing)422 edid_detailed_timing_is_monitor_descriptor(const struct edid * const edid,
423                                            const uint8_t timing)
424 {
425     const struct edid_monitor_descriptor * const mon =
426         &edid->detailed_timings[timing].monitor;
427 
428     assert(timing < ARRAY_SIZE(edid->detailed_timings));
429 
430     return mon->flag0 == 0x0000 && mon->flag1 == 0x00 && mon->flag2 == 0x00;
431 }
432 
433 
434 struct __attribute__ (( packed )) edid_color_characteristics_data {
435     struct {
436         uint16_t x;
437         uint16_t y;
438     } red, green, blue, white;
439 };
440 
441 static inline struct edid_color_characteristics_data
edid_color_characteristics(const struct edid * const edid)442 edid_color_characteristics(const struct edid * const edid)
443 {
444     const struct edid_color_characteristics_data characteristics = {
445         .red = {
446             .x = (edid->red_x << 2) | edid->red_x_low,
447             .y = (edid->red_y << 2) | edid->red_y_low,
448         },
449         .green = {
450             .x = (edid->green_x << 2) | edid->green_x_low,
451             .y = (edid->green_y << 2) | edid->green_y_low,
452         },
453         .blue = {
454             .x = (edid->blue_x << 2) | edid->blue_x_low,
455             .y = (edid->blue_y << 2) | edid->blue_y_low,
456         },
457         .white = {
458             .x = (edid->white_x << 2) | edid->white_x_low,
459             .y = (edid->white_y << 2) | edid->white_y_low,
460         },
461     };
462 
463     return characteristics;
464 }
465 
466 
467 struct __attribute__ (( packed )) edid_block_map {
468     uint8_t tag;
469     uint8_t extension_tag[126];
470     uint8_t checksum;
471 };
472 
473 
474 struct __attribute__ (( packed )) edid_extension {
475     uint8_t tag;
476     uint8_t revision;
477     uint8_t extension_data[125];
478     uint8_t checksum;
479 };
480 
481 
482 static inline bool
edid_verify_checksum(const uint8_t * const block)483 edid_verify_checksum(const uint8_t * const block)
484 {
485     uint8_t checksum = 0;
486     int i;
487 
488     for (i = 0; i < EDID_BLOCK_SIZE; i++)
489         checksum += block[i];
490 
491     return (checksum == 0);
492 }
493 
494 static inline double
edid_decode_fixed_point(uint16_t value)495 edid_decode_fixed_point(uint16_t value)
496 {
497     double result = 0.0;
498 
499     assert((~value & 0xfc00) == 0xfc00);    /* edid fraction is 10 bits */
500 
501     for (uint8_t i = 0; value && (i < 10); i++, value >>= 1)
502         result = result + ((value & 0x1) * (1.0 / (1 << (10 - i))));
503 
504     return result;
505 }
506 
507 #endif
508 
509