2 *-----------------------------------------------------------------------------
3 * Filename: displayid.c
5 *-----------------------------------------------------------------------------
6 * Copyright (c) 2002-2010, Intel Corporation.
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 *-----------------------------------------------------------------------------
28 * This file contains functions to parse DisplayID into a data strucuture.
29 * Supported DisplayID versions:
30 * VESA DisplayID Standard Verion 1 12/13/2007
31 *-----------------------------------------------------------------------------
34 #define MODULE_NAME hal.dpd
39 #include <igd_errno.h>
41 #include <displayid.h>
45 * @addtogroup display_group
49 #ifndef CONFIG_NO_DISPLAYID
52 * Keep the order of datablocks as it is.
53 * DisplayID parser directly access the offset using tag as an index.
55 unsigned short db_offset[] = {
57 OS_OFFSETOF(displayid_t, dummy_db), /* PRODUCTID 0x00 */
58 OS_OFFSETOF(displayid_t, display_params), /* DISPLAY_PARAMS 0x01 */
59 OS_OFFSETOF(displayid_t, dummy_db), /* COLOR_CHARS 0x02 */
60 OS_OFFSETOF(displayid_t, dummy_db), /* TIMING_1_DETAIL 0x03 */
61 OS_OFFSETOF(displayid_t, dummy_db), /* TIMING_2_DETAIL 0x04 */
62 OS_OFFSETOF(displayid_t, dummy_db), /* TIMING_3_SHORT 0x05 */
63 OS_OFFSETOF(displayid_t, dummy_db), /* TIMING_4_DMTID 0x06 */
64 OS_OFFSETOF(displayid_t, dummy_db), /* VESA_TIMING_STD 0x07 */
65 OS_OFFSETOF(displayid_t, dummy_db), /* CEA_TIMING_STD 0x08 */
66 OS_OFFSETOF(displayid_t, timing_range), /* VIDEO_RANGE 0x09 */
67 OS_OFFSETOF(displayid_t, dummy_db), /* SERIAL_NUMBER 0x0A */
68 OS_OFFSETOF(displayid_t, dummy_db), /* ASCII_STRING 0x0B */
69 OS_OFFSETOF(displayid_t, display_dev), /* DISPLAY_DEVICE 0x0C */
70 OS_OFFSETOF(displayid_t, lvds), /* LVDS_INTERFACE 0x0D */
71 OS_OFFSETOF(displayid_t, dummy_db), /* TRANSFER_CHAR 0x0E */
72 OS_OFFSETOF(displayid_t, display_intf), /* DISPLAY_INTF 0x0F */
73 OS_OFFSETOF(displayid_t, dummy_db), /* STEREO_INTF 0x10 */
75 OS_OFFSETOF(displayid_t, productid), /* PRODUCTID 0x00 */
76 OS_OFFSETOF(displayid_t, display_params), /* DISPLAY_PARAMS 0x01 */
77 OS_OFFSETOF(displayid_t, color_char), /* COLOR_CHARS 0x02 */
78 OS_OFFSETOF(displayid_t, dummy_db), /* TIMING_1_DETAIL 0x03 */
79 OS_OFFSETOF(displayid_t, dummy_db), /* TIMING_2_DETAIL 0x04 */
80 OS_OFFSETOF(displayid_t, dummy_db), /* TIMING_3_SHORT 0x05 */
81 OS_OFFSETOF(displayid_t, dummy_db), /* TIMING_4_DMTID 0x06 */
82 OS_OFFSETOF(displayid_t, dummy_db), /* VESA_TIMING_STD 0x07 */
83 OS_OFFSETOF(displayid_t, dummy_db), /* CEA_TIMING_STD 0x08 */
84 OS_OFFSETOF(displayid_t, timing_range), /* VIDEO_RANGE 0x09 */
85 OS_OFFSETOF(displayid_t, serial_num), /* SERIAL_NUMBER 0x0A */
86 OS_OFFSETOF(displayid_t, general_string), /* ASCII_STRING 0x0B */
87 OS_OFFSETOF(displayid_t, display_dev), /* DISPLAY_DEVICE 0x0C */
88 OS_OFFSETOF(displayid_t, lvds), /* LVDS_INTERFACE 0x0D */
89 OS_OFFSETOF(displayid_t, transfer_char), /* TRANSFER_CHAR 0x0E */
90 OS_OFFSETOF(displayid_t, display_intf), /* DISPLAY_INTF 0x0F */
91 OS_OFFSETOF(displayid_t, stereo_intf), /* STEREO_INTF 0x10 */
96 /* Vendor specific tag is out of order, so it cannot be here. See
97 * case DATABLOCK_VENDOR_SPECIFIC for implementation. */
98 OS_OFFSETOF(displayid_t, vendor), /* VENDOR_SPECIFIC 0x7F */
102 type_std_t vesa_std_lookup[] =
104 /* width height refresh flags */
105 /* byte 0 bit 0->7 */
106 { 640, 350, 85, 0 }, /* bit 0 */
107 { 640, 400, 85, 0 }, /* bit 1 */
108 { 720, 400, 85, 0 }, /* bit 2 */
109 { 640, 480, 60, 0 }, /* bit 3 */
110 { 640, 480, 72, 0 }, /* bit 4 */
111 { 640, 480, 75, 0 }, /* bit 5 */
112 { 640, 480, 85, 0 }, /* bit 6 */
113 { 800, 600, 56, 0 }, /* bit 7 */
115 /* byte 1 bit 0->7 */
116 { 800, 600, 60, 0 }, /* bit 0 */
117 { 800, 600, 72, 0 }, /* bit 1 */
118 { 800, 600, 75, 0 }, /* bit 2 */
119 { 800, 600, 85, 0 }, /* bit 3 */
120 { 800, 600, 120, PD_MODE_RB }, /* bit 4 */
121 { 848, 480, 60, 0 }, /* bit 5 */
122 { 1024, 768, 43, PD_SCAN_INTERLACE }, /* bit 6 */
123 { 1024, 768, 60, 0 }, /* bit 7 */
125 /* byte 2 bit 0->7 */
126 { 1024, 768, 70, 0 }, /* bit 0 */
127 { 1024, 768, 75, 0 }, /* bit 1 */
128 { 1024, 768, 85, 0 }, /* bit 2 */
129 { 1024, 768, 120, PD_MODE_RB }, /* bit 3 */
130 { 1152, 864, 75, 0 }, /* bit 4 */
131 { 1280, 768, 60, PD_MODE_RB }, /* bit 5 */
132 { 1280, 768, 60, 0 }, /* bit 6 */
133 { 1280, 768, 75, 0 }, /* bit 7 */
135 /* byte 3 bit 0->7 */
136 { 1280, 768, 85, 0 }, /* bit 0 */
137 { 1280, 768, 120, PD_MODE_RB }, /* bit 1 */
138 { 1280, 800, 60, PD_MODE_RB }, /* bit 2 */
139 { 1280, 800, 60, 0 }, /* bit 3 */
140 { 1280, 800, 75, 0 }, /* bit 4 */
141 { 1280, 800, 85, 0 }, /* bit 5 */
142 { 1280, 800, 120, PD_MODE_RB }, /* bit 6 */
143 { 1280, 960, 60, 0 }, /* bit 7 */
145 /* byte 4 bit 0->7 */
146 { 1280, 960, 85, 0 }, /* bit 0 */
147 { 1280, 960, 120, PD_MODE_RB }, /* bit 1 */
148 { 1280, 1024, 60, 0 }, /* bit 2 */
149 { 1280, 1024, 75, 0 }, /* bit 3 */
150 { 1280, 1024, 85, 0 }, /* bit 4 */
151 { 1280, 1024, 120, PD_MODE_RB }, /* bit 5 */
152 { 1360, 768, 60, 0 }, /* bit 6 */
153 { 1360, 768, 120, PD_MODE_RB }, /* bit 7 */
155 /* byte 5 bit 0->7 */
156 { 1400, 1050, 60, PD_MODE_RB }, /* bit 0 */
157 { 1400, 1050, 60, 0 }, /* bit 1 */
158 { 1400, 1050, 75, 0 }, /* bit 2 */
159 { 1400, 1050, 85, 0 }, /* bit 3 */
160 { 1400, 1050, 120, PD_MODE_RB }, /* bit 4 */
161 { 1440, 900, 60, PD_MODE_RB }, /* bit 5 */
162 { 1440, 900, 60, 0 }, /* bit 6 */
163 { 1440, 900, 75, 0 }, /* bit 7 */
165 /* byte 6 bit 0->7 */
166 { 1440, 900, 85, 0 }, /* bit 0 */
167 { 1440, 900, 120, PD_MODE_RB }, /* bit 1 */
168 { 1600, 1200, 60, 0 }, /* bit 2 */
169 { 1600, 1200, 65, 0 }, /* bit 3 */
170 { 1600, 1200, 70, 0 }, /* bit 4 */
171 { 1600, 1200, 75, 0 }, /* bit 5 */
172 { 1600, 1200, 85, 0 }, /* bit 6 */
173 { 1600, 1200, 120, PD_MODE_RB }, /* bit 7 */
175 /* byte 7 bit 0->7 */
176 { 1680, 1050, 60, PD_MODE_RB }, /* bit 0 */
177 { 1680, 1050, 60, 0 }, /* bit 1 */
178 { 1680, 1050, 75, 0 }, /* bit 2 */
179 { 1680, 1050, 85, 0 }, /* bit 3 */
180 { 1680, 1050, 120, PD_MODE_RB }, /* bit 4 */
181 { 1792, 1344, 60, 0 }, /* bit 5 */
182 { 1792, 1344, 75, 0 }, /* bit 6 */
183 { 1792, 1344, 120, PD_MODE_RB }, /* bit 7 */
185 /* byte 8 bit 0->7 */
186 { 1856, 1392, 60, 0 }, /* bit 0 */
187 { 1856, 1392, 75, 0 }, /* bit 1 */
188 { 1856, 1392, 120, PD_MODE_RB }, /* bit 2 */
189 { 1920, 1200, 60, PD_MODE_RB }, /* bit 3 */
190 { 1920, 1200, 60, 0 }, /* bit 4 */
191 { 1920, 1200, 75, 0 }, /* bit 5 */
192 { 1920, 1200, 85, 0 }, /* bit 6 */
193 { 1920, 1200, 120, PD_MODE_RB }, /* bit 7 */
195 /* byte 9 bit 0->7 */
196 { 1920, 1440, 60, 0 }, /* bit 0 */
197 { 1920, 1440, 75, 0 }, /* bit 1 */
198 { 1920, 1440, 120, PD_MODE_RB }, /* bit 2 */
199 { 2560, 1600, 60, PD_MODE_RB }, /* bit 3 */
200 { 2560, 1600, 60, 0 }, /* bit 4 */
201 { 2560, 1600, 75, 0 }, /* bit 5 */
202 { 2560, 1600, 85, 0 }, /* bit 6 */
203 { 2560, 1600, 120, PD_MODE_RB }, /* bit 7 */
208 * Function to replace common timings in 1st list with 2nd list, 2nd list
216 void replace_vesa_dtds_with_cea_dtds(igd_timing_info_t *dtds1,
217 igd_timing_info_t *dtds2)
219 igd_timing_info_t *temp;
221 if (!dtds2 || !dtds1) {
225 while (dtds1->width != IGD_TIMING_TABLE_END) {
228 while (temp->width != IGD_TIMING_TABLE_END) {
229 if ((temp->width == dtds1->width) &&
230 (temp->height == dtds1->height) &&
231 (temp->refresh == dtds1->refresh)) {
232 dtds1->mode_info_flags &= ~PD_MODE_SUPPORTED;
241 #ifdef DEBUG_FIRMWARE
248 void displayid_print_datablock(datablock_t *db)
250 unsigned char payload_string[800];
253 /* Get the payload data into a string */
254 OS_MEMSET(payload_string, 0, sizeof(payload_string));
255 for (i=0, j=0; i<db->payload; i++,j+=5) {
256 payload_string[j] = '0';
257 payload_string[j+1] = 'x';
258 if ((db->payload_data[i]>>4) <= 0x9) {
259 payload_string[j+2] = '0' + (db->payload_data[i]>>4);
261 payload_string[j+2] = 'A' + (db->payload_data[i]>>4) - 0xA;
263 if ((db->payload_data[i] & 0x0F) <= 0x9) {
264 payload_string[j+3] = '0' + (db->payload_data[i]&0x0F);
266 payload_string[j+3] = 'A' + (db->payload_data[i]&0x0F) - 0xA;
268 payload_string[j+4] = ' ';
270 payload_string[j] = '\0';
272 EMGD_DEBUG("Tag = %u", db->tag);
273 EMGD_DEBUG("Version = %u", db->revision);
274 EMGD_DEBUG("Payload = %u", db->payload);
275 EMGD_DEBUG("Payload data = %s", payload_string);
285 void displayid_print(unsigned char *buffer, displayid_t *did)
288 display_params_t *dp = &did->display_params;
289 timing_range_t *tr = &did->timing_range;
290 lvds_display_t *ld = &did->lvds;
291 display_dev_t *dd = &did->display_dev;
292 display_intf_t *di = &did->display_intf;
294 productid_t *pi = &did->productid;
295 color_char_t *cc = &did->color_char;
296 serial_number_t *sn = &did->serial_num;
297 general_string_t *gs = &did->general_string;
298 transfer_char_t *tc = &did->transfer_char;
299 stereo_intf_t *si = &did->stereo_intf;
300 vendor_t *vi = &did->vendor;
303 DISPLAYID_PRINT_LINE();
304 EMGD_DEBUG("DisplayID Version: %d", did->version);
305 EMGD_DEBUG("DisplayID Revision: %d", did->revision);
306 DISPLAYID_PRINT_LINE();
307 EMGD_DEBUG("Size of different structures:");
308 DISPLAYID_PRINT_LINE();
309 EMGD_DEBUG(" displayid_t = %d", sizeof(displayid_t));
310 EMGD_DEBUG("display_params_t = %d", sizeof(display_params_t));
311 EMGD_DEBUG(" type1_dtd_t = %d", sizeof(type1_dtd_t));
312 EMGD_DEBUG(" type2_dtd_t = %d", sizeof(type2_dtd_t));
313 EMGD_DEBUG(" type3_cvt_t = %d", sizeof(type3_cvt_t));
314 EMGD_DEBUG(" type_std_t = %d", sizeof(type_std_t));
315 EMGD_DEBUG(" timing_range_t = %d", sizeof(timing_range_t));
316 EMGD_DEBUG(" display_dev_t = %d", sizeof(display_dev_t));
317 EMGD_DEBUG(" lvds_display_t = %d", sizeof(lvds_display_t));
318 EMGD_DEBUG(" display_intf_t = %d", sizeof(display_intf_t));
319 EMGD_DEBUG(" dummy_db = %d", 256);
320 EMGD_DEBUG(" timings = %d",
321 sizeof(pd_timing_t)*DISPLAYID_MAX_NUM_TIMINGS);
322 EMGD_DEBUG(" attrs = %d",
323 sizeof(pd_attr_t)*DISPLAYID_MAX_ATTRS);
326 EMGD_DEBUG(" productid_t = %d", sizeof(productid_t));
327 EMGD_DEBUG(" color_char_t = %d", sizeof(color_char_t));
328 EMGD_DEBUG(" serial_number_t = %d", sizeof(serial_number_t));
329 EMGD_DEBUG("general_string_t = %d", sizeof(general_string_t));
330 EMGD_DEBUG(" transfer_char_t = %d", sizeof(transfer_char_t));
331 EMGD_DEBUG(" stereo_intf_t = %d", sizeof(stereo_intf_t));
332 EMGD_DEBUG(" vendor_t = %d", sizeof(vendor_t));
334 DISPLAYID_PRINT_LINE();
335 EMGD_DEBUG("PRODUCT ID DATA BLOCK");
336 DISPLAYID_PRINT_LINE();
337 displayid_print_datablock((datablock_t *)pi);
338 EMGD_DEBUG(" vendor = %c%c%c",
339 pi->vendor[0], pi->vendor[1], pi->vendor[2]);
340 EMGD_DEBUG(" product_code = %u", pi->product_code);
341 EMGD_DEBUG("serial_number = %lu", pi->serial_number);
342 EMGD_DEBUG(" manf_week = %u", pi->manf_week);
343 EMGD_DEBUG(" manf_year = %u", pi->manf_year+2000);
344 EMGD_DEBUG(" string_len = %u", pi->string_size);
345 EMGD_DEBUG(" string = %s", pi->string);
347 DISPLAYID_PRINT_LINE();
348 EMGD_DEBUG("COLOR CHARACTERISTICS DATA BLOCK");
349 DISPLAYID_PRINT_LINE();
350 displayid_print_datablock((datablock_t *)cc);
352 DISPLAYID_PRINT_LINE();
353 EMGD_DEBUG("SERIAL NUMBER DATA BLOCK");
354 DISPLAYID_PRINT_LINE();
355 displayid_print_datablock((datablock_t *)sn);
357 DISPLAYID_PRINT_LINE();
358 EMGD_DEBUG("GENERAL PURPOSE ASCII STRING DATA BLOCK");
359 DISPLAYID_PRINT_LINE();
360 displayid_print_datablock((datablock_t *)gs);
362 DISPLAYID_PRINT_LINE();
363 EMGD_DEBUG("TRANSFER CHARACTERISTICS DATA BLOCK");
364 DISPLAYID_PRINT_LINE();
365 displayid_print_datablock((datablock_t *)tc);
367 DISPLAYID_PRINT_LINE();
368 EMGD_DEBUG("STEREO INTERFACE DATA BLOCK");
369 DISPLAYID_PRINT_LINE();
370 displayid_print_datablock((datablock_t *)si);
372 DISPLAYID_PRINT_LINE();
373 EMGD_DEBUG("VENDOR SPECIFIC DATA BLOCK");
374 DISPLAYID_PRINT_LINE();
375 displayid_print_datablock((datablock_t *)vi);
378 DISPLAYID_PRINT_LINE();
379 EMGD_DEBUG("DISPLAY PARAMETERS DATA BLOCK");
380 DISPLAYID_PRINT_LINE();
381 displayid_print_datablock((datablock_t *)dp);
382 EMGD_DEBUG("horz_image_size = %u", dp->horz_image_size);
383 EMGD_DEBUG("vert_image_size = %u", dp->vert_image_size);
384 EMGD_DEBUG(" horz_pixels = %u", dp->horz_pixels);
385 EMGD_DEBUG(" vert_pixels = %u", dp->vert_pixels);
386 EMGD_DEBUG(" deinterlacable = %u", dp->deinterlacing);
387 EMGD_DEBUG(" fixed_timing = %u", dp->fixed_timing);
388 EMGD_DEBUG(" fixed_res = %u", dp->fixed_res);
389 EMGD_DEBUG(" aspect_ratio = %u", dp->aspect_ratio);
390 EMGD_DEBUG(" native_color_depth(bppc) = %u", dp->native_color_depth+1);
391 EMGD_DEBUG("overall_color_depth(bppc) = %u", dp->overall_color_depth+1);
393 DISPLAYID_PRINT_LINE();
394 EMGD_DEBUG("VIDEO TIMING RANGESS DATA BLOCK");
395 DISPLAYID_PRINT_LINE();
396 displayid_print_datablock((datablock_t *)tr);
397 EMGD_DEBUG(" min_dclk = %lu KHz", tr->min_dclk);
398 EMGD_DEBUG(" max_dclk = %lu KHz", tr->max_dclk);
399 EMGD_DEBUG(" min_hrate = %u KHz", tr->min_hrate);
400 EMGD_DEBUG(" max_hrate = %u KHz", tr->max_hrate);
401 EMGD_DEBUG("min_hblank = %u pixels", tr->min_hblank);
402 EMGD_DEBUG(" min_vrate = %u Hz", tr->min_vrate);
403 EMGD_DEBUG(" max_vrate = %u Hz", tr->max_vrate);
404 EMGD_DEBUG("min_vblank = %u lines", tr->min_vblank);
406 DISPLAYID_PRINT_LINE();
407 EMGD_DEBUG("LVDS DISPLAY DATA BLOCK");
408 DISPLAYID_PRINT_LINE();
409 displayid_print_datablock((datablock_t *)ld);
410 EMGD_DEBUG("min_T1 = %u ms", ld->min_t1/10);
411 EMGD_DEBUG("max_T1 = %u ms", ld->max_t1*2);
412 EMGD_DEBUG("max_T2 = %u ms", ld->max_t2*2);
413 EMGD_DEBUG("max_T3 = %u ms", ld->max_t3*2);
414 EMGD_DEBUG("min_T4 = %u ms", ld->min_t4*10);
415 EMGD_DEBUG("min_T5 = %u ms", ld->min_t5*10);
416 EMGD_DEBUG("min_T6 = %u ms", ld->min_t6*10);
418 DISPLAYID_PRINT_LINE();
419 EMGD_DEBUG("DISPLAY DEVICE DATA BLOCK");
420 DISPLAYID_PRINT_LINE();
421 displayid_print_datablock((datablock_t *)dd);
422 EMGD_DEBUG(" horz_pixel_count = %u", dd->horz_pixel_count);
423 EMGD_DEBUG(" vert_pixel_count = %u", dd->vert_pixel_count);
424 EMGD_DEBUG("display_color_depth = %u", dd->display_color_depth);
426 DISPLAYID_PRINT_LINE();
427 EMGD_DEBUG("DISPLAY INTERFACE DATA BLOCK");
428 DISPLAYID_PRINT_LINE();
429 displayid_print_datablock((datablock_t *)di);
430 EMGD_DEBUG(" num_channels = %u", di->num_channels);
431 EMGD_DEBUG(" intf_type = %u", di->intf_type);
432 EMGD_DEBUG(" RGB_color_depth = %u", di->rgb_color_depth);
433 EMGD_DEBUG("YCrCb_444_color_depth = %u", di->ycbcr_444_color_depth);
434 EMGD_DEBUG("YCrCb_422_color_depth = %u", di->ycbcr_422_color_depth);
435 if(di->intf_type == INTERFACE_LVDS) {
436 EMGD_DEBUG(" openldi = %u", di->lvds.openldi);
439 DISPLAYID_PRINT_LINE();
440 EMGD_DEBUG("Detailed Timing Descriptors");
441 DISPLAYID_PRINT_LINE();
443 for (i=0; i<did->num_timings; i++) {
444 EMGD_DEBUG("DTD: %u", i+1);
445 EMGD_DEBUG(" dclk = %lu", did->timings[i].dclk);
446 EMGD_DEBUG(" hactive = %u", did->timings[i].width);
447 EMGD_DEBUG(" htotal = %u", did->timings[i].htotal);
448 EMGD_DEBUG(" hblank_start = %u", did->timings[i].hblank_start);
449 EMGD_DEBUG(" hsync_start = %u", did->timings[i].hsync_start);
450 EMGD_DEBUG(" hsync_end = %u", did->timings[i].hsync_end);
451 EMGD_DEBUG(" hblank_end = %u", did->timings[i].hblank_end);
452 EMGD_DEBUG(" vactive = %u", did->timings[i].height);
453 EMGD_DEBUG(" vtotal = %u", did->timings[i].vtotal);
454 EMGD_DEBUG(" vblank_start = %u", did->timings[i].vblank_start);
455 EMGD_DEBUG(" vsync_start = %u", did->timings[i].vsync_start);
456 EMGD_DEBUG(" vsync_end = %u", did->timings[i].vsync_end);
457 EMGD_DEBUG(" vblank_end = %u", did->timings[i].vblank_end);
458 EMGD_DEBUG(" native = %u",
459 (did->timings[i].mode_info_flags&PD_MODE_DTD_FP_NATIVE)?1:0);
460 EMGD_DEBUG(" interlace = %u",
461 (did->timings[i].mode_info_flags&PD_SCAN_INTERLACE)?1:0);
462 EMGD_DEBUG("hsync_polarity = %s",
463 (did->timings[i].mode_info_flags & PD_HSYNC_HIGH)?
464 "ACTIVE HIGH":"ACTIVE LOW");
465 EMGD_DEBUG("vsync_polarity = %s",
466 (did->timings[i].mode_info_flags & PD_VSYNC_HIGH)?
467 "ACTIVE HIGH":"ACTIVE LOW");
468 DISPLAYID_PRINT_LINE();
471 /* Print the attributes */
472 if (did->num_attrs) {
473 EMGD_DEBUG("\tAttr\tID\tVALUE");
474 EMGD_DEBUG("----------------------");
475 for (i=0; i<did->num_attrs; i++) {
476 EMGD_DEBUG("\t%u\t%lu\t%lu", i+1, did->attr_list[i].id,
477 did->attr_list[i].current_value);
479 EMGD_DEBUG("----------------------");
485 * Function to convert Type I - Detailed to pd_timing_t
492 void convert_type1_to_pd(pd_timing_t *timing, type1_dtd_t *dtd)
494 unsigned long refresh;
495 timing->dclk = /* change to KHz */
496 ((unsigned long)dtd->dclk.lsb_dclk|
497 ((unsigned long)dtd->dclk.msb_dclk<<16))*10;
499 /* DisplayID fields are 0 based but should be interpreted as 1-based.
500 * For example hsync_width value can be read as 0-65,535 pixels but
501 * interpreted as 1-65,536. So, to get the right value add 1.
502 * But pd_timing_t values are 0 based except width and height,
503 * so care should be taken while converting DisplayID fields into
504 * pd_timing_t values */
505 timing->hblank_start = dtd->hactive;
506 timing->width = dtd->hactive + 1;
507 timing->hblank_end = timing->hblank_start + dtd->hblank + 1;
508 timing->hsync_start = timing->hblank_start + dtd->hsync_offset + 1;
509 timing->hsync_end = timing->hsync_start + dtd->hsync_width + 1;
510 timing->htotal = timing->hblank_end;
512 timing->vblank_start = dtd->vactive;
513 timing->height = dtd->vactive + 1;
514 timing->vblank_end = timing->vblank_start + dtd->vblank + 1;
515 timing->vsync_start = timing->vblank_start + dtd->vsync_offset + 1;
516 timing->vsync_end = timing->vsync_start + dtd->vsync_width + 1;
517 timing->vtotal = timing->vblank_end;
519 refresh = ((timing->dclk * 1000L)/timing->htotal)/timing->vtotal;
520 timing->refresh = (unsigned short) refresh;
522 timing->mode_info_flags = PD_MODE_DTD|PD_MODE_SUPPORTED;
523 if (dtd->hsync_polarity) {
524 timing->mode_info_flags |= PD_HSYNC_HIGH;
526 if (dtd->vsync_polarity) {
527 timing->mode_info_flags |= PD_VSYNC_HIGH;
529 if (dtd->interlaced) {
530 timing->mode_info_flags |= PD_SCAN_INTERLACE;
532 if (dtd->preferred) {
533 timing->mode_info_flags |= PD_MODE_DTD_FP_NATIVE;
538 * Function to convert Type II - Detailed to pd_timing_t
545 void convert_type2_to_pd(pd_timing_t *timing, type2_dtd_t *dtd)
547 unsigned long refresh;
548 timing->dclk = /* change to KHz */
549 ((unsigned long)dtd->dclk.lsb_dclk|
550 ((unsigned long)dtd->dclk.msb_dclk<<16))*10;
552 /* DisplayID fields are 0 based but should be interpreted as 1-based.
553 * For example hsync_width value can be read as 0-15 OCTETs but
554 * interpreted as 1-16 OCTETs. So, to get the right value add 1.
555 * But pd_timing_t values are 0 based except width and height,
556 * so care should be taken while converting DisplayID fields into
557 * pd_timing_t values */
558 timing->width = (dtd->hactive + 1) * 8; /* change to pixels */
559 timing->hblank_start = timing->width - 1;
560 timing->hblank_end = timing->hblank_start + (dtd->hblank + 1) * 8;
561 timing->hsync_start = timing->hblank_start + (dtd->hsync_offset + 1) * 8;
562 timing->hsync_end = timing->hsync_start + (dtd->hsync_width + 1) * 8;
563 timing->htotal = timing->hblank_end;
565 timing->vblank_start = dtd->vactive;
566 timing->height = dtd->vactive + 1;
567 timing->vblank_end = timing->vblank_start + dtd->vblank + 1;
568 timing->vsync_start = timing->vblank_start + dtd->vsync_offset + 1;
569 timing->vsync_end = timing->vsync_start + dtd->vsync_width + 1;
570 timing->vtotal = timing->vblank_end;
572 refresh = ((timing->dclk * 1000L)/timing->htotal)/timing->vtotal;
573 timing->refresh = (unsigned short) refresh;
575 timing->mode_info_flags = PD_MODE_DTD|PD_MODE_SUPPORTED;
576 if (dtd->interlaced) {
577 timing->mode_info_flags |= PD_SCAN_INTERLACE;
579 if (dtd->preferred) {
580 timing->mode_info_flags |= PD_MODE_DTD_FP_NATIVE;
585 * Function to filter timing table based on range block
589 * @param firmware_type
593 void displayid_filter_range_timings(pd_timing_t *tt, timing_range_t *range,
594 unsigned char firmware_type)
596 unsigned short hfreq;
598 #define _HUNDRETHS(_n, _d) ((100*_n)/_d)-((100*_n_d)/100),
600 #ifdef DEBUG_FIRMWARE
602 unsigned char pass_count = 0;
603 unsigned char fail_count = 0;
605 EMGD_DEBUG("Range limits:");
606 EMGD_DEBUG("\tmin_dclk = %lu KHz max_dclk = %lu KHz",
607 range->min_dclk, range->max_dclk);
608 EMGD_DEBUG("\t h_min = %u h_max = %u KHz",
609 range->min_hrate, range->max_hrate);
610 EMGD_DEBUG("\t v_min = %u v_max = %u",
611 range->min_vrate,range->max_vrate);
612 EMGD_DEBUG("WIDTH\tHEIGHT\tREFRESH\tH-FREQ\tDOTCLOCK\tRESULT");
613 EMGD_DEBUG(" \t \t (Hz) \t (KHz)\t (MHz) \t ");
614 EMGD_DEBUG("=====\t======\t=======\t======\t========\t======");
617 /* If the display is a discreate frequency display, don't enable any
618 * intermediate timings. Only continuous frequency displays requires
619 * enabling range timings */
620 if (range->discrete_display) {
621 EMGD_DEBUG("Discrete display: Ranges aren't used.");
625 /* If no timing table return */
630 /* Mark the timings that fall in the ranges */
635 while(tt->width != IGD_TIMING_TABLE_END) {
636 hfreq = (unsigned short)(tt->dclk/(unsigned long)tt->htotal); /* KHz */
637 if ((tt->dclk >= (unsigned long)range->min_dclk)&& /* compare KHz */
638 (tt->dclk <= (unsigned long)range->max_dclk)&& /* compare KHz */
639 (tt->refresh >= range->min_vrate) && /* compare Hz */
640 (tt->refresh <= range->max_vrate) && /* compare Hz */
641 (hfreq >= range->min_hrate) && /* compare KHz */
642 (hfreq <= range->max_hrate) && /* compare KHz */
643 (tt->hblank_end - tt->hblank_start) > range->min_hblank &&
644 (tt->vblank_end - tt->vblank_start) > range->min_vblank) {
645 tt->mode_info_flags |= PD_MODE_SUPPORTED;
646 #ifdef DEBUG_FIRMWARE
647 if (tt->mode_info_flags & PD_MODE_SUPPORTED) {
648 EMGD_DEBUG("%5u\t%6u\t%7u\t%6u.%2u\t%8u.%2u\tPASSED",
649 tt->width, tt->height, tt->refresh,
651 _HUNDRETHS(tt->dclk,tt->htotal),
653 _HUNDRETHS(tt->dclk,1000);
660 /* Unmark the mode that falls out of range */
661 /* DTD, FACTORY and NATIVE timings are "GOLD" even if they
662 * fall outside the range limits */
663 if (!(tt->mode_info_flags &
664 (PD_MODE_DTD|PD_MODE_FACTORY|PD_MODE_DTD_FP_NATIVE))) {
665 #ifdef DEBUG_FIRMWARE
666 if ((tt->dclk < /* compare KHz */
667 (unsigned long)range->min_dclk)||
669 (unsigned long)range->max_dclk)) {
670 OS_MEMCPY(result_str, "FAILED DCLK \0", 16);
672 } else if ((tt->refresh > range->max_vrate) ||
673 (tt->refresh < range->min_vrate)) {
674 OS_MEMCPY(result_str, "FAILED REFRESH \0", 16);
676 } else if ((hfreq < range->min_hrate) ||
677 (hfreq > range->max_hrate)) {
678 OS_MEMCPY(result_str, "FAILED H-FREQ \0", 16);
680 } else if ((tt->hblank_end-tt->hblank_start) <
682 OS_MEMCPY(result_str, "FAILED MIN_HBLK\0", 16);
683 } else if ((tt->vblank_end-tt->vblank_start) <
685 OS_MEMCPY(result_str, "FAILED MIN_VBLK\0", 16);
687 EMGD_DEBUG("%5u\t%6u\t%7u\t%6u.%2u\t%8u.%2u\t%s",
688 tt->width, tt->height, tt->refresh,
690 _HUNDRETHS(tt->dclk,tt->htotal),
692 _HUNDRETHS(tt->dclk,1000),
694 ((float) tt->dclk)/1000, result_str);
696 /* TODO: For multiple range blocks, don't disable the modes
697 * that are outside the range. We already started with
698 * an "empty supported table" */
700 /* But above assertion of "empty supported table" broke
701 * if EDID ETF rules were met to enable all timings.
702 * See edid.c for ETF conditions. So below line
703 * cannot be commented out to support multiple range
704 * blocks for DisplayID. */
706 tt->mode_info_flags &= ~PD_MODE_SUPPORTED;
710 if (tt->width == IGD_TIMING_TABLE_END && tt->extn_ptr) {
714 #ifdef DEBUG_FIRMWARE
715 EMGD_DEBUG("pass count = %u, fail count = %u total = %u",
716 pass_count, fail_count, pass_count+fail_count);
718 } /* end displayid_filter_range_timings() */
724 * Function to enable std timings: VESA STD or CEA STD
734 void displayid_enable_std_timings(pd_timing_t *tt1, unsigned char *db_data,
735 type_std_t *lookup, unsigned short num_lookup, unsigned char std_type)
739 /* If no timing table return. This can happen if no edid_avail set not to
745 /* For every factory supported mode, enable it in the timing table */
746 for (i = 0; i < num_lookup; i++) {
748 /* i>>3 is nothing but dividing by 8, that gives the byte number,
749 * i&0x7 is nothing but getting the bit position in that byte */
750 if (db_data[i>>3] & 1<<(i&0x7)) {
751 while(tt->width != IGD_TIMING_TABLE_END) {
752 if (lookup[i].width == tt->width &&
753 lookup[i].height == tt->height &&
755 (!((lookup[i].flags & (PD_SCAN_INTERLACE|PD_MODE_RB)) ^
756 (tt->mode_info_flags & (PD_SCAN_INTERLACE|PD_MODE_RB)))) &&
758 (!((lookup[i].flags & PD_SCAN_INTERLACE) ^
759 (tt->mode_info_flags & PD_SCAN_INTERLACE))) &&
760 (!((lookup[i].flags & PD_ASPECT_16_9) ^
761 (tt->mode_info_flags & PD_ASPECT_16_9))) &&
762 lookup[i].refresh == tt->refresh) {
763 tt->mode_info_flags |= (PD_MODE_FACTORY|PD_MODE_SUPPORTED);
767 if (tt->width == IGD_TIMING_TABLE_END && tt->extn_ptr) {
775 static void displayid_parse_orientation_info (unsigned char orientation_blob,
776 igd_DID_rotation_info_t * rotation_info) {
778 unsigned int def_orientation = DEFAULT_ORIENTATION(orientation_blob);
779 unsigned int zero_pixel = ZERO_PIXEL(orientation_blob);
780 unsigned int scan_dir = SCAN_DIRECTION(orientation_blob);
782 /* Start with no rotation */
783 rotation_info->rotation = 0;
784 rotation_info->flip = 0;
787 if (def_orientation >= DEF_ORIENTATION_UNKNOWN) {
788 /* Display ID blob is corrupted or unknown configuration set */
789 EMGD_DEBUG("DisplayID: Unknown default orientation value: %d",
794 if (scan_dir == SCAN_DIRECTION_LONG) {
795 if (def_orientation == DEF_ORIENTATION_PORTRAIT) {
796 rotation_info->flip =
797 (zero_pixel == ZP_UPPER_LEFT || zero_pixel == ZP_LOWER_RIGHT);
798 rotation_info->rotation += 90;
799 } else { /* Landscape */
800 rotation_info->flip =
801 (zero_pixel == ZP_UPPER_RIGHT || zero_pixel == ZP_LOWER_LEFT);
804 } else if (scan_dir == SCAN_DIRECTION_SHORT) {
805 if (def_orientation == DEF_ORIENTATION_PORTRAIT) {
806 rotation_info->flip =
807 (zero_pixel == ZP_UPPER_RIGHT || zero_pixel == ZP_LOWER_LEFT);
809 else { /* Landscape */
810 rotation_info->flip =
811 (zero_pixel == ZP_UPPER_LEFT || zero_pixel == ZP_LOWER_RIGHT);
812 rotation_info->rotation += 90;
814 } else { /* Unknown scan direction */
815 EMGD_DEBUG("DisplayID: Unknown scan direction value: %d", scan_dir);
819 /* zero pixel is in the lower-half: need to rotate by 180 degs */
820 if (zero_pixel == ZP_LOWER_LEFT || zero_pixel == ZP_LOWER_RIGHT)
821 rotation_info->rotation += 180;
825 * Function to parse DisplayID
829 * @param timing_table
836 unsigned char *buffer,
838 pd_timing_t *timing_table,
840 unsigned char upscale)
842 //unsigned char e = 0;
843 unsigned char checksum = 0, bytes_left;
845 unsigned short did_size;
847 pd_timing_t *cea_tmg_table;
849 /* Read 4 bytes: (DisplayID Header)
852 * display product type identifier
853 * number of extensions */
854 *(unsigned long *) did = *(unsigned long *)buffer;
856 /* Check for version and revision */
857 if (did->version != 1 && did->revision != 0) {
858 EMGD_DEBUG("DisplayID Version %d.%d Unknown. Will Ignore.",
859 did->version, did->revision);
860 return DISPLAYID_NOT_SUPPORTED;
863 if (did->payload > 251) {
864 EMGD_DEBUG("DispID: Error: payload = %u not in [0..251]", did->payload);
865 return DISPLAYID_ERROR_PARSE;
868 /* Check sum check */
869 /* +5 is for 5 mandatory bytes */
870 did_size = (unsigned short) (did->payload + 5);
871 EMGD_DEBUG("DisplayID size = %u", did_size);
872 for (i = 0; i < did_size; i++) {
873 checksum += buffer[i];
876 /* bytes_left starts without DisplayID header */
877 bytes_left = did->payload;
878 /* current pointer is at 4 not at 5, because checksum byte is at the end */
882 EMGD_DEBUG("DisplayID checksum is incorrect! Will ignore.");
883 return DISPLAYID_ERROR_PARSE;
886 /* DisplayID parsing should start by disabling all modes.
887 * Based on DisplayID data blocks modes will be enabled. */
888 enable_disable_timings(timing_table, 0);
890 /* Repeat for all extensions */
891 //e = did->num_extensions;
894 //if (e != did->num_extensions) {
895 /* TODO: If there aren't enough bytes left in the buffer,
896 * call I2C read function to read next DisplayID section */
898 /* Skip next section header 4 bytes */
903 /* Parse Data Blocks */
904 /* Check minimum number of bytes required for Data Block were left */
905 while ((bytes_left > 3) && (bytes_left >= (buffer[2]+3))) {
906 unsigned char *db_data;
907 unsigned char payload = buffer[2] + 3;
909 /* displayid->datablock = buffer (for payload bytes) */
910 if (buffer[0] < sizeof(db_offset)/sizeof(unsigned short)) {
911 OS_MEMCPY(((unsigned char*)did) + db_offset[buffer[0]],
915 /* db_data points to payload data after db header (3 bytes),
916 * Note: dummy_db offset is used for some DATA BLOCKS. See
917 * db_offset table above. */
918 db_data = (unsigned char *) &did->dummy_db[3];
921 /* Supported in Driver and VBIOS */
922 case DATABLOCK_DISPLAY_PARAMS:
923 /* Use following fields for fp_info:
924 * embedded use: fixed timing
925 * horizontal pixels: fp_width
926 * vertical pixels: fp_height */
927 did->attr_list[did->num_attrs].id = PD_ATTR_ID_PANEL_DEPTH;
928 did->attr_list[did->num_attrs].flags=PD_ATTR_FLAG_VALUE_CHANGED;
929 did->attr_list[did->num_attrs++].current_value =
930 (did->display_params.overall_color_depth+1)*3;
933 case DATABLOCK_TIMING_1_DETAIL:
934 /* One Type I block can have multiple DTDs */
935 while (payload>=20&&did->num_timings<DISPLAYID_MAX_NUM_TIMINGS){
936 convert_type1_to_pd(&did->timings[did->num_timings++],
937 (type1_dtd_t *)db_data);
943 /* Mark the end of the list */
944 did->timings[did->num_timings].width = IGD_TIMING_TABLE_END;
947 case DATABLOCK_TIMING_2_DETAIL:
948 /* One Type II block can have multiple DTDs */
949 while (payload>=11&&did->num_timings<DISPLAYID_MAX_NUM_TIMINGS){
950 convert_type2_to_pd(&did->timings[did->num_timings++],
951 (type2_dtd_t *)db_data);
957 did->timings[did->num_timings].width = IGD_TIMING_TABLE_END;
960 case DATABLOCK_VESA_TIMING_STD:
961 /* VESA Standard Timings */
962 displayid_enable_std_timings(
966 sizeof(vesa_std_lookup)/sizeof(type_std_t),
970 case DATABLOCK_VIDEO_RANGE:
971 /* convert from Hz/10,000 -> KHz by multiplying by 10 */
972 did->timing_range.min_dclk =
973 ((unsigned long)did->timing_range.mindclk.lsb_min_dclk|
974 ((unsigned long)did->timing_range.mindclk.msb_min_dclk
977 did->timing_range.max_dclk =
978 ((unsigned long)did->timing_range.maxdclk.lsb_max_dclk|
979 ((unsigned long)did->timing_range.maxdclk.msb_max_dclk
981 displayid_filter_range_timings(timing_table,&did->timing_range,
982 PI_FIRMWARE_DISPLAYID);
985 case DATABLOCK_DISPLAY_DEVICE:
986 /* Get panel color depth */
987 did->attr_list[did->num_attrs].id = PD_ATTR_ID_PANEL_DEPTH;
988 did->attr_list[did->num_attrs].flags=PD_ATTR_FLAG_VALUE_CHANGED;
989 did->attr_list[did->num_attrs++].current_value =
990 (did->display_dev.display_color_depth+1)*3;
991 displayid_parse_orientation_info(did->display_dev.orientation,
992 &(did->rotation_info));
995 case DATABLOCK_LVDS_INTERFACE:
996 /* Get T1-T5 values */
997 did->attr_list[did->num_attrs].id = PD_ATTR_ID_FP_PWR_T1;
998 did->attr_list[did->num_attrs].flags=PD_ATTR_FLAG_VALUE_CHANGED;
999 did->attr_list[did->num_attrs++].current_value =
1000 did->lvds.max_t1*2 + did->lvds.max_t2*2;
1002 did->attr_list[did->num_attrs].id = PD_ATTR_ID_FP_PWR_T2;
1003 did->attr_list[did->num_attrs].flags=PD_ATTR_FLAG_VALUE_CHANGED;
1004 did->attr_list[did->num_attrs++].current_value =
1005 did->lvds.min_t5*10;
1007 did->attr_list[did->num_attrs].id = PD_ATTR_ID_FP_PWR_T3;
1008 did->attr_list[did->num_attrs].flags=PD_ATTR_FLAG_VALUE_CHANGED;
1009 did->attr_list[did->num_attrs++].current_value =
1010 did->lvds.min_t6*10;
1012 did->attr_list[did->num_attrs].id = PD_ATTR_ID_FP_PWR_T4;
1013 did->attr_list[did->num_attrs].flags=PD_ATTR_FLAG_VALUE_CHANGED;
1014 did->attr_list[did->num_attrs++].current_value =
1017 did->attr_list[did->num_attrs].id = PD_ATTR_ID_FP_PWR_T5;
1018 did->attr_list[did->num_attrs].flags=PD_ATTR_FLAG_VALUE_CHANGED;
1019 did->attr_list[did->num_attrs++].current_value =
1020 did->lvds.min_t4*10 + did->lvds.max_t1*2;
1023 case DATABLOCK_DISPLAY_INTF:
1024 if (did->display_intf.intf_type == INTERFACE_LVDS) {
1025 /* Get number of channels: 0=singlechannel 1=dualchannel */
1026 did->attr_list[did->num_attrs].id =
1027 PD_ATTR_ID_2_CHANNEL_PANEL;
1028 did->attr_list[did->num_attrs].flags =
1029 PD_ATTR_FLAG_VALUE_CHANGED;
1030 if (did->display_intf.num_channels == 2) {
1031 did->attr_list[did->num_attrs++].current_value = 1;
1034 /* Get panel type value: 0=normal 1=OpenLDI */
1035 did->attr_list[did->num_attrs].id =
1036 PD_ATTR_ID_LVDS_PANEL_TYPE;
1037 did->attr_list[did->num_attrs].flags =
1038 PD_ATTR_FLAG_VALUE_CHANGED;
1039 did->attr_list[did->num_attrs++].current_value =
1040 did->display_intf.lvds.openldi;
1045 #ifndef CONFIG_MICRO
1046 /* Support in Driver only */
1047 case DATABLOCK_PRODUCTID:
1050 case DATABLOCK_SERIAL_NUMBER:
1053 case DATABLOCK_ASCII_STRING:
1056 case DATABLOCK_VENDOR_SPECIFIC:
1057 /* Because vendor specific datablock tag is out-of-order,
1058 * copy data from buffer to vendor structure */
1059 OS_MEMCPY(&did->vendor, buffer, buffer[2] + 3);
1062 /* Future support in Driver and VBIOS */
1063 case DATABLOCK_TIMING_3_SHORT:
1066 case DATABLOCK_TIMING_4_DMTID:
1069 /* Future support in Driver */
1070 case DATABLOCK_COLOR_CHARS:
1073 case DATABLOCK_CEA_TIMING_STD:
1074 cea_tmg_table = (igd_timing_info_t *)
1075 OS_ALLOC(cea_timing_table_size);
1076 OS_MEMCPY(cea_tmg_table, cea_timing_table,
1077 cea_timing_table_size);
1078 /* Disable the CEA timings */
1079 enable_disable_timings(cea_tmg_table, 0);
1080 displayid_enable_std_timings(
1084 (unsigned short)cea_std_lookup_size,
1087 replace_vesa_dtds_with_cea_dtds(timing_table, cea_tmg_table);
1088 cea_tmg_table[cea_timing_table_size-1].extn_ptr =
1089 (void *)timing_table;
1090 timing_table = cea_tmg_table;
1093 case DATABLOCK_TRANSFER_CHAR:
1097 /* Subtract data block payload */
1098 bytes_left -= payload;
1101 /* Extension count */