2
*-----------------------------------------------------------------------------
3
* Filename: displayid.c
5
*-----------------------------------------------------------------------------
6
* Copyright © 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) {
776
* Function to parse DisplayID
780
* @param timing_table
787
unsigned char *buffer,
789
pd_timing_t *timing_table,
791
unsigned char upscale)
793
//unsigned char e = 0;
794
unsigned char checksum = 0, bytes_left;
796
unsigned short did_size;
798
pd_timing_t *cea_tmg_table;
800
/* Read 4 bytes: (DisplayID Header)
803
* display product type identifier
804
* number of extensions */
805
*(unsigned long *) did = *(unsigned long *)buffer;
807
/* Check for version and revision */
808
if (did->version != 1 && did->revision != 0) {
809
EMGD_DEBUG("DisplayID Version %d.%d Unknown. Will Ignore.",
810
did->version, did->revision);
811
return DISPLAYID_NOT_SUPPORTED;
814
if (did->payload > 251) {
815
EMGD_DEBUG("DispID: Error: payload = %u not in [0..251]", did->payload);
816
return DISPLAYID_ERROR_PARSE;
819
/* Check sum check */
820
/* +5 is for 5 mandatory bytes */
821
did_size = (unsigned short) (did->payload + 5);
822
EMGD_DEBUG("DisplayID size = %u", did_size);
823
for (i = 0; i < did_size; i++) {
824
checksum += buffer[i];
827
/* bytes_left starts without DisplayID header */
828
bytes_left = did->payload;
829
/* current pointer is at 4 not at 5, because checksum byte is at the end */
833
EMGD_DEBUG("DisplayID checksum is incorrect! Will ignore.");
834
return DISPLAYID_ERROR_PARSE;
837
/* DisplayID parsing should start by disabling all modes.
838
* Based on DisplayID data blocks modes will be enabled. */
839
enable_disable_timings(timing_table, 0);
841
/* Repeat for all extensions */
842
//e = did->num_extensions;
845
//if (e != did->num_extensions) {
846
/* TODO: If there aren't enough bytes left in the buffer,
847
* call I2C read function to read next DisplayID section */
849
/* Skip next section header 4 bytes */
854
/* Parse Data Blocks */
855
/* Check minimum number of bytes required for Data Block were left */
856
while ((bytes_left > 3) && (bytes_left >= (buffer[2]+3))) {
857
unsigned char *db_data;
858
unsigned char payload = buffer[2] + 3;
860
/* displayid->datablock = buffer (for payload bytes) */
861
if (buffer[0] < sizeof(db_offset)/sizeof(unsigned short)) {
862
OS_MEMCPY(((unsigned char*)did) + db_offset[buffer[0]],
866
/* db_data points to payload data after db header (3 bytes),
867
* Note: dummy_db offset is used for some DATA BLOCKS. See
868
* db_offset table above. */
869
db_data = (unsigned char *) &did->dummy_db[3];
872
/* Supported in Driver and VBIOS */
873
case DATABLOCK_DISPLAY_PARAMS:
874
/* Use following fields for fp_info:
875
* embedded use: fixed timing
876
* horizontal pixels: fp_width
877
* vertical pixels: fp_height */
878
did->attr_list[did->num_attrs].id = PD_ATTR_ID_PANEL_DEPTH;
879
did->attr_list[did->num_attrs].flags=PD_ATTR_FLAG_VALUE_CHANGED;
880
did->attr_list[did->num_attrs++].current_value =
881
(did->display_params.overall_color_depth+1)*3;
884
case DATABLOCK_TIMING_1_DETAIL:
885
/* One Type I block can have multiple DTDs */
886
while (payload>=20&&did->num_timings<DISPLAYID_MAX_NUM_TIMINGS){
887
convert_type1_to_pd(&did->timings[did->num_timings++],
888
(type1_dtd_t *)db_data);
894
/* Mark the end of the list */
895
did->timings[did->num_timings].width = IGD_TIMING_TABLE_END;
898
case DATABLOCK_TIMING_2_DETAIL:
899
/* One Type II block can have multiple DTDs */
900
while (payload>=11&&did->num_timings<DISPLAYID_MAX_NUM_TIMINGS){
901
convert_type2_to_pd(&did->timings[did->num_timings++],
902
(type2_dtd_t *)db_data);
908
did->timings[did->num_timings].width = IGD_TIMING_TABLE_END;
911
case DATABLOCK_VESA_TIMING_STD:
912
/* VESA Standard Timings */
913
displayid_enable_std_timings(
917
sizeof(vesa_std_lookup)/sizeof(type_std_t),
921
case DATABLOCK_VIDEO_RANGE:
922
/* convert from Hz/10,000 -> KHz by multiplying by 10 */
923
did->timing_range.min_dclk =
924
((unsigned long)did->timing_range.mindclk.lsb_min_dclk|
925
((unsigned long)did->timing_range.mindclk.msb_min_dclk
928
did->timing_range.max_dclk =
929
((unsigned long)did->timing_range.maxdclk.lsb_max_dclk|
930
((unsigned long)did->timing_range.maxdclk.msb_max_dclk
932
displayid_filter_range_timings(timing_table,&did->timing_range,
933
PI_FIRMWARE_DISPLAYID);
936
case DATABLOCK_DISPLAY_DEVICE:
937
/* Get panel color depth */
938
did->attr_list[did->num_attrs].id = PD_ATTR_ID_PANEL_DEPTH;
939
did->attr_list[did->num_attrs].flags=PD_ATTR_FLAG_VALUE_CHANGED;
940
did->attr_list[did->num_attrs++].current_value =
941
(did->display_dev.display_color_depth+1)*3;
944
case DATABLOCK_LVDS_INTERFACE:
945
/* Get T1-T5 values */
946
did->attr_list[did->num_attrs].id = PD_ATTR_ID_FP_PWR_T1;
947
did->attr_list[did->num_attrs].flags=PD_ATTR_FLAG_VALUE_CHANGED;
948
did->attr_list[did->num_attrs++].current_value =
949
did->lvds.max_t1*2 + did->lvds.max_t2*2;
951
did->attr_list[did->num_attrs].id = PD_ATTR_ID_FP_PWR_T2;
952
did->attr_list[did->num_attrs].flags=PD_ATTR_FLAG_VALUE_CHANGED;
953
did->attr_list[did->num_attrs++].current_value =
956
did->attr_list[did->num_attrs].id = PD_ATTR_ID_FP_PWR_T3;
957
did->attr_list[did->num_attrs].flags=PD_ATTR_FLAG_VALUE_CHANGED;
958
did->attr_list[did->num_attrs++].current_value =
961
did->attr_list[did->num_attrs].id = PD_ATTR_ID_FP_PWR_T4;
962
did->attr_list[did->num_attrs].flags=PD_ATTR_FLAG_VALUE_CHANGED;
963
did->attr_list[did->num_attrs++].current_value =
966
did->attr_list[did->num_attrs].id = PD_ATTR_ID_FP_PWR_T5;
967
did->attr_list[did->num_attrs].flags=PD_ATTR_FLAG_VALUE_CHANGED;
968
did->attr_list[did->num_attrs++].current_value =
969
did->lvds.min_t4*10 + did->lvds.max_t1*2;
972
case DATABLOCK_DISPLAY_INTF:
973
if (did->display_intf.intf_type == INTERFACE_LVDS) {
974
/* Get number of channels: 0=singlechannel 1=dualchannel */
975
did->attr_list[did->num_attrs].id =
976
PD_ATTR_ID_2_CHANNEL_PANEL;
977
did->attr_list[did->num_attrs].flags =
978
PD_ATTR_FLAG_VALUE_CHANGED;
979
if (did->display_intf.num_channels == 2) {
980
did->attr_list[did->num_attrs++].current_value = 1;
983
/* Get panel type value: 0=normal 1=OpenLDI */
984
did->attr_list[did->num_attrs].id =
985
PD_ATTR_ID_LVDS_PANEL_TYPE;
986
did->attr_list[did->num_attrs].flags =
987
PD_ATTR_FLAG_VALUE_CHANGED;
988
did->attr_list[did->num_attrs++].current_value =
989
did->display_intf.lvds.openldi;
995
/* Support in Driver only */
996
case DATABLOCK_PRODUCTID:
999
case DATABLOCK_SERIAL_NUMBER:
1002
case DATABLOCK_ASCII_STRING:
1005
case DATABLOCK_VENDOR_SPECIFIC:
1006
/* Because vendor specific datablock tag is out-of-order,
1007
* copy data from buffer to vendor structure */
1008
OS_MEMCPY(&did->vendor, buffer, buffer[2] + 3);
1011
/* Future support in Driver and VBIOS */
1012
case DATABLOCK_TIMING_3_SHORT:
1015
case DATABLOCK_TIMING_4_DMTID:
1018
/* Future support in Driver */
1019
case DATABLOCK_COLOR_CHARS:
1022
case DATABLOCK_CEA_TIMING_STD:
1023
cea_tmg_table = (igd_timing_info_t *)
1024
OS_ALLOC(cea_timing_table_size);
1025
OS_MEMCPY(cea_tmg_table, cea_timing_table,
1026
cea_timing_table_size);
1027
/* Disable the CEA timings */
1028
enable_disable_timings(cea_tmg_table, 0);
1029
displayid_enable_std_timings(
1033
(unsigned short)cea_std_lookup_size,
1036
replace_vesa_dtds_with_cea_dtds(timing_table, cea_tmg_table);
1037
cea_tmg_table[cea_timing_table_size-1].extn_ptr =
1038
(void *)timing_table;
1039
timing_table = cea_tmg_table;
1042
case DATABLOCK_TRANSFER_CHAR:
1046
/* Subtract data block payload */
1047
bytes_left -= payload;
1050
/* Extension count */
1059
/*----------------------------------------------------------------------------
1060
* File Revision History
1061
* $Id: displayid.c,v 1.7 2011/02/16 17:04:48 astead Exp $
1062
* $Source: /nfs/fm/proj/eia/cvsroot/koheo/linux/egd_drm/emgd/display/pi/cmn/displayid.c,v $
1063
*----------------------------------------------------------------------------