1 //*****************************************************************************
2 //
3 // SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
4 // SPDX-License-Identifier: MIT
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a
7 // copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the 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 // File: nvt_edid.c
25 //
26 // Purpose: the provide edid related services
27 //
28 //*****************************************************************************
29
30 #include "nvBinSegment.h"
31 #include "nvmisc.h"
32
33 #include "edid.h"
34
35
36
37 PUSH_SEGMENTS
38
39 // Macro to declare a TIMING initializer for given parameters without border
40 #define EST_TIMING(hv,hfp,hsw,ht,hsp,vv,vfp,vsw,vt,vsp,rr,pclk,format) \
41 {hv,0,hfp,hsw,ht,(hsp)=='-',vv,0,vfp,vsw,vt,(vsp)=='-',NVT_PROGRESSIVE,pclk,{0,rr,set_rrx1k(pclk,ht,vt),0,1,{0},{0},{0},{0},format,"VESA Established"}}
42
43 DATA_SEGMENT(PAGE_DATA)
44 #if !defined(NV_WSA)
45 CONS_SEGMENT(PAGE_CONS)
46 #endif // wsa
47
48 // There is a large table of strings that translate 3-character PNP vendor IDs to a more user-friendly name in the following header.
49 // Mark this constant table as pageable.
50 #include "nvPNPVendorIds.h"
51
52 static const NVT_TIMING EDID_EST[] =
53 {
54 EST_TIMING( 720, 0, 0, 720,'-', 400, 0,0, 400,'-',70, 0,NVT_STATUS_EDID_EST), // 720x400x70Hz (IBM, VGA)
55 EST_TIMING( 720, 0, 0, 720,'-', 400, 0,0, 400,'-',88, 0,NVT_STATUS_EDID_EST), // 720x400x88Hz (IBM, XGA2)
56 {640,0,16,96,800,NVT_H_SYNC_NEGATIVE,480,0,10,2,525,NVT_V_SYNC_NEGATIVE,NVT_PROGRESSIVE,2518,{0,60,60000,0,1,{0},{0},{0},{0},NVT_STATUS_EDID_EST,"EDID_Established"}},
57
58 EST_TIMING( 640, 0, 0, 640,'-', 480, 0,0, 480,'-',67, 0,NVT_STATUS_EDID_EST), // 640x480x67Hz (Apple, Mac II)
59
60 // 640x480x72Hz (VESA) - this entry have borders
61 {640,8,16,40,832,NVT_H_SYNC_NEGATIVE,480,8,1,3,520,NVT_V_SYNC_NEGATIVE,NVT_PROGRESSIVE,3150,{0,72,72000,0,1,{0},{0},{0},{0},NVT_STATUS_EDID_EST,"EDID_Established"}},
62 EST_TIMING( 640,16, 64, 840,'-', 480, 1,3, 500,'-',75, 3150,NVT_STATUS_EDID_EST), // 640x480x75Hz (VESA)
63 EST_TIMING( 800,24, 72,1024,'+', 600, 1,2, 625,'+',56, 3600,NVT_STATUS_EDID_EST), // 800x600x56Hz (VESA)
64 EST_TIMING( 800,40,128,1056,'+', 600, 1,4, 628,'+',60, 4000,NVT_STATUS_EDID_EST), // 800x600x60Hz (VESA)
65
66 EST_TIMING( 800,56,120,1040,'+', 600,37,6, 666,'+',72, 5000,NVT_STATUS_EDID_EST), // 800x600x72Hz (VESA)
67 EST_TIMING( 800,16, 80,1056,'+', 600, 1,3, 625,'+',75, 4950,NVT_STATUS_EDID_EST), // 800x600x75Hz (VESA)
68 EST_TIMING( 832, 0, 0, 832,'-', 624, 0,0, 624,'-',75, 0,NVT_STATUS_EDID_EST), // 832x624x75Hz (Apple, Mac II)
69 EST_TIMING(1024, 0, 0,1024,'-', 768, 0,0, 768,'-',87, 0,NVT_STATUS_EDID_EST), // 1024x768x87Hz (IBM, Interlaced)
70
71 EST_TIMING(1024,24,136,1344,'-', 768, 3,6, 806,'-',60, 6500,NVT_STATUS_EDID_EST), // 1024x768x60Hz (VESA)
72 EST_TIMING(1024,24,136,1328,'-', 768, 3,6, 806,'-',70, 7500,NVT_STATUS_EDID_EST), // 1024x768x70Hz (VESA)
73 EST_TIMING(1024,16, 96,1312,'+', 768, 1,3, 800,'+',75, 7875,NVT_STATUS_EDID_EST), // 1024x768x75Hz (VESA)
74 EST_TIMING(1280,16,144,1688,'+',1024, 1,3,1066,'+',75,13500,NVT_STATUS_EDID_EST), // 1280x1024x75Hz (VESA)
75
76 // the end
77 NVT_TIMING_SENTINEL
78 };
79
80 static NvU32 MAX_EST_FORMAT = sizeof(EDID_EST)/sizeof(EDID_EST[0]) - 1;
81
82 static const NVT_TIMING EDID_ESTIII[] =
83 {
84 EST_TIMING( 640, 32, 64, 832,'+', 350,32,3, 445,'-',85, 3150,NVT_STATUS_EDID_EST), // 640x350x85Hz
85 EST_TIMING( 640, 32, 64, 832,'-', 400, 1,3, 445,'+',85, 3150,NVT_STATUS_EDID_EST), // 640x400x85Hz
86 EST_TIMING( 720, 36, 72, 936,'-', 400, 1,3, 446,'+',85, 3550,NVT_STATUS_EDID_EST), // 720x400x85Hz
87 EST_TIMING( 640, 56, 56, 832,'-', 480, 1,3, 509,'-',85, 3600,NVT_STATUS_EDID_EST), // 640x480x85Hz
88 EST_TIMING( 848, 16,112,1088,'+', 480, 6,8, 517,'+',60, 3375,NVT_STATUS_EDID_EST), // 848x480x60HZ
89 EST_TIMING( 800, 32, 64,1048,'+', 600, 1,3, 631,'+',85, 5625,NVT_STATUS_EDID_EST), // 800x600x85Hz
90 EST_TIMING(1024, 48, 96,1376,'+', 768, 1,3, 808,'+',85, 9450,NVT_STATUS_EDID_EST), // 1024x768x85Hz
91 EST_TIMING(1152, 64,128,1600,'+', 864, 1,3, 900,'+',75,10800,NVT_STATUS_EDID_EST), // 1152x864x75Hz
92
93 EST_TIMING(1280, 48, 32,1440,'+', 768, 3,7, 790,'-',60, 6825,NVT_STATUS_EDID_EST), // 1280x768x60Hz (RB)
94 EST_TIMING(1280, 64,128,1664,'-', 768, 3,7, 798,'+',60, 7950,NVT_STATUS_EDID_EST), // 1280x768x60Hz
95 EST_TIMING(1280, 80,128,1696,'-', 768, 3,7, 805,'+',75,10225,NVT_STATUS_EDID_EST), // 1280x768x75Hz
96 EST_TIMING(1280, 80,136,1712,'-', 768, 3,7, 809,'+',85,11750,NVT_STATUS_EDID_EST), // 1280x768x85Hz
97 EST_TIMING(1280, 96,112,1800,'+', 960, 1,3,1000,'+',60,10800,NVT_STATUS_EDID_EST), // 1280x960x60Hz
98 EST_TIMING(1280, 64,160,1728,'+', 960, 1,3,1011,'+',85,14850,NVT_STATUS_EDID_EST), // 1280x960x85Hz
99 EST_TIMING(1280, 48,112,1688,'+',1024, 1,3,1066,'+',60,10800,NVT_STATUS_EDID_EST), // 1280x1024x60Hz
100 EST_TIMING(1280, 64,160,1728,'+',1024, 1,3,1072,'+',85,15750,NVT_STATUS_EDID_EST), // 1280x1024x85Hz
101
102 EST_TIMING(1360, 64,112,1792,'+', 768, 3,6, 795,'+',60, 8550,NVT_STATUS_EDID_EST), // 1360x768x60Hz
103 EST_TIMING(1440, 48, 32,1600,'+', 900, 3,6, 926,'-',60, 8875,NVT_STATUS_EDID_EST), // 1440x900x60Hz (RB)
104 EST_TIMING(1440, 80,152,1904,'-', 900, 3,6, 934,'+',60,10650,NVT_STATUS_EDID_EST), // 1440x900x60Hz
105 EST_TIMING(1440, 96,152,1936,'-', 900, 3,6, 942,'+',75,13675,NVT_STATUS_EDID_EST), // 1440x900x75Hz
106 EST_TIMING(1440,104,152,1952,'-', 900, 3,6, 948,'+',85,15700,NVT_STATUS_EDID_EST), // 1440x900x85Hz
107 EST_TIMING(1400, 48, 32,1560,'+',1050, 3,4,1080,'-',60,10100,NVT_STATUS_EDID_EST), // 1440x1050x60Hz (RB)
108 EST_TIMING(1400, 88,144,1864,'-',1050, 3,4,1089,'+',60,12175,NVT_STATUS_EDID_EST), // 1440x1050x60Hz
109 EST_TIMING(1400,104,144,1896,'-',1050, 3,4,1099,'+',75,15600,NVT_STATUS_EDID_EST), // 1440x1050x75Hz
110
111 EST_TIMING(1400,104,152,1912,'-',1050, 3,4,1105,'+',85,17950,NVT_STATUS_EDID_EST), // 1440x1050x85Hz
112 EST_TIMING(1680, 48, 32,1840,'+',1050, 3,6,1080,'-',60,11900,NVT_STATUS_EDID_EST), // 1680x1050x60Hz (RB)
113 EST_TIMING(1680,104,176,2240,'-',1050, 3,6,1089,'+',60,14625,NVT_STATUS_EDID_EST), // 1680x1050x60Hz
114 EST_TIMING(1680,120,176,2272,'-',1050, 3,6,1099,'+',75,18700,NVT_STATUS_EDID_EST), // 1680x1050x75Hz
115 EST_TIMING(1680,128,176,2288,'-',1050, 3,6,1105,'+',85,21475,NVT_STATUS_EDID_EST), // 1680x1050x85Hz
116 EST_TIMING(1600, 64,192,2160,'+',1200, 1,3,1250,'+',60,16200,NVT_STATUS_EDID_EST), // 1600x1200x60Hz
117 EST_TIMING(1600, 64,192,2160,'+',1200, 1,3,1250,'+',65,17550,NVT_STATUS_EDID_EST), // 1600x1200x65Hz
118 EST_TIMING(1600, 64,192,2160,'+',1200, 1,3,1250,'+',70,18900,NVT_STATUS_EDID_EST), // 1600x1200x70Hz
119
120 EST_TIMING(1600, 64,192,2160,'+',1200, 1,3,1250,'+',75,20250,NVT_STATUS_EDID_EST), // 1600x1200x75Hz
121 EST_TIMING(1600, 64,192,2160,'+',1200, 1,3,1250,'+',85,22950,NVT_STATUS_EDID_EST), // 1600x1200x85Hz
122 EST_TIMING(1792,128,200,2448,'-',1344, 1,3,1394,'+',60,20475,NVT_STATUS_EDID_EST), // 1792x1344x60Hz
123 EST_TIMING(1792, 96,216,2456,'-',1344, 1,3,1417,'+',75,26100,NVT_STATUS_EDID_EST), // 1792x1344x75Hz
124 EST_TIMING(1856, 96,224,2528,'-',1392, 1,3,1439,'+',60,21825,NVT_STATUS_EDID_EST), // 1856x1392x60Hz
125 EST_TIMING(1856,128,224,2560,'-',1392, 1,3,1500,'+',75,28800,NVT_STATUS_EDID_EST), // 1856x1392x75Hz
126 EST_TIMING(1920, 48, 32,2080,'+',1200, 3,6,1235,'-',60,15400,NVT_STATUS_EDID_EST), // 1920x1200x60Hz (RB)
127 EST_TIMING(1920,136,200,2592,'-',1200, 3,6,1245,'+',60,19325,NVT_STATUS_EDID_EST), // 1920x1200x60Hz
128
129 EST_TIMING(1920,136,208,2608,'-',1200, 3,6,1255,'+',75,24525,NVT_STATUS_EDID_EST), // 1920x1200x75Hz
130 EST_TIMING(1920,144,208,2624,'-',1200, 3,6,1262,'+',85,28125,NVT_STATUS_EDID_EST), // 1920x1200x85Hz
131 EST_TIMING(1920,128,208,2600,'-',1440, 1,3,1500,'+',60,23400,NVT_STATUS_EDID_EST), // 1920x1440x60Hz
132 EST_TIMING(1920,144,224,2640,'-',1440, 1,3,1500,'+',75,29700,NVT_STATUS_EDID_EST), // 1920x1440x75Hz
133
134 NVT_TIMING_SENTINEL,
135 NVT_TIMING_SENTINEL,
136 NVT_TIMING_SENTINEL,
137 NVT_TIMING_SENTINEL
138 };
139
140 static NvU32 MAX_ESTIII_FORMAT = sizeof(EDID_ESTIII)/sizeof(EDID_ESTIII[0]) - 1;
141
CODE_SEGMENT(PAGE_DD_CODE)142 CODE_SEGMENT(PAGE_DD_CODE)
143 NVT_STATUS NvTiming_EnumEST(NvU32 index, NVT_TIMING *pT)
144 {
145 if ((pT == NULL) || (index > MAX_EST_FORMAT))
146 {
147 return NVT_STATUS_ERR;
148 }
149
150 *pT = EDID_EST[index];
151
152 if (pT->HTotal == 0 || pT->VTotal == 0)
153 {
154 return NVT_STATUS_ERR;
155 }
156
157 pT->etc.rrx1k = axb_div_c((NvU32)pT->pclk,
158 (NvU32)10000*(NvU32)1000,
159 (NvU32)pT->HTotal*(NvU32)pT->VTotal);
160
161 return NVT_STATUS_SUCCESS;
162 }
163
CODE_SEGMENT(PAGE_DD_CODE)164 CODE_SEGMENT(PAGE_DD_CODE)
165 NVT_STATUS NvTiming_EnumESTIII(NvU32 index, NVT_TIMING *pT)
166 {
167 if ((pT == NULL) || (index > MAX_ESTIII_FORMAT))
168 {
169 return NVT_STATUS_ERR;
170 }
171
172 *pT = EDID_ESTIII[index];
173
174 if (pT->HTotal == 0 || pT->VTotal == 0)
175 {
176 return NVT_STATUS_ERR;
177 }
178
179 pT->etc.rrx1k = axb_div_c((NvU32)pT->pclk,
180 (NvU32)10000*(NvU32)1000,
181 (NvU32)pT->HTotal*(NvU32)pT->VTotal);
182
183 return NVT_STATUS_SUCCESS;
184 }
185
CODE_SEGMENT(PAGE_DD_CODE)186 CODE_SEGMENT(PAGE_DD_CODE)
187 NvU32 isHdmi3DStereoType(NvU8 StereoStructureType)
188 {
189 return ((NVT_HDMI_VS_BYTE5_HDMI_3DS_FRAMEPACK == StereoStructureType) ||
190 (NVT_HDMI_VS_BYTE5_HDMI_3DS_FIELD_ALT == StereoStructureType) ||
191 (NVT_HDMI_VS_BYTE5_HDMI_3DS_LINE_ALT == StereoStructureType) ||
192 (NVT_HDMI_VS_BYTE5_HDMI_3DS_SIDEBYSIDEFULL == StereoStructureType) ||
193 (NVT_HDMI_VS_BYTE5_HDMI_3DS_LDEPTH == StereoStructureType) ||
194 (NVT_HDMI_VS_BYTE5_HDMI_3DS_LDEPTHGFX == StereoStructureType) ||
195 (NVT_HDMI_VS_BYTE5_HDMI_3DS_TOPBOTTOM == StereoStructureType) ||
196 (NVT_HDMI_VS_BYTE5_HDMI_3DS_SIDEBYSIDEHALF == StereoStructureType));
197 }
198
CODE_SEGMENT(PAGE_DD_CODE)199 CODE_SEGMENT(PAGE_DD_CODE)
200 NvU32 NvTiming_GetVESADisplayDescriptorVersion(NvU8 *rawData, NvU32 *pVer)
201 {
202 return getEdidVersion(rawData, pVer);
203 }
204
205 // get the EDID version
CODE_SEGMENT(PAGE_DD_CODE)206 CODE_SEGMENT(PAGE_DD_CODE)
207 NvU32 getEdidVersion(NvU8 *pEdid, NvU32 *pVer)
208 {
209 EDIDV1STRUC *p = (EDIDV1STRUC *) pEdid;
210
211 if (pEdid[0] == 0x00)
212 {
213 // For Version 1.x, first 8 bytes of EDID must be 00h, FFh, FFh, FFh, FFh, FFh, FFh, 00h.
214 // Beware of Endian-ness and signed-ness.
215 if (p->bHeader[1] != 0xFF || p->bHeader[2] != 0xFF || p->bHeader[3] != 0xFF ||
216 p->bHeader[4] != 0xFF || p->bHeader[5] != 0xFF || p->bHeader[6] != 0xFF ||
217 p->bHeader[7] != 0x00)
218 return NVT_STATUS_ERR;
219
220 *pVer = (((NvU32) p->bVersionNumber) << 8) + ((NvU32) p->bRevisionNumber);
221 }
222 else if ((pEdid[0] & 0xF0) == 0x20)
223 *pVer = (((NvU32) (pEdid[0] & 0XF0) << 4) + (NvU32) (pEdid[0] & 0X0F)) ; // DisplayID version 2.x
224 else
225 return NVT_STATUS_ERR; // un-recongnized EDID version
226
227 return NVT_STATUS_SUCCESS;
228 }
229
CODE_SEGMENT(PAGE_DD_CODE)230 CODE_SEGMENT(PAGE_DD_CODE)
231 void parseEdidCvt3ByteDescriptor(NvU8 *p, NVT_EDID_INFO *pInfo, NvU32 *vtbCount)
232 {
233 NvU32 k;
234 NvU32 width, height, aspect, rr = 0;
235 NVT_EDID_DD_CVT_3BYTE_BLOCK *pTiming = (NVT_EDID_DD_CVT_3BYTE_BLOCK *)p;
236 NVT_TIMING newTiming;
237 NVT_STATUS status;
238
239
240 if (pTiming->addressable_lines == 0)
241 return;
242
243 height = pTiming->addressable_lines;
244 aspect = pTiming->aspect_ratio;
245
246 if (aspect == NVT_EDID_CVT3_ASPECT_4X3)
247 width = height * 4 / 3;
248 else if (aspect == NVT_EDID_CVT3_ASPECT_16X9)
249 width = height * 16 / 9;
250 else if (aspect == NVT_EDID_CVT3_ASPECT_16X10)
251 width = height * 16 / 10;
252 else //15:9
253 width = height * 15 / 9;
254
255 width &= 0xFFFFFFF8; // round down to nearest 8
256
257 // loop through bits4:0 of supported_vert_rate so we can add a timing
258 // for each supported rate
259 for (k=1; k<=0x10; k<<=1)
260 {
261 // skip if this bit indicate no support for the rate;
262 if ( (pTiming->supported_vert_rates & (k)) == 0)
263 continue;
264
265 // find the correct refresh rate for this bit
266 switch (k)
267 {
268 case NVT_EDID_CVT3_SUPPORTED_RATE_60HZ_REDUCED_BLANKING :
269 case NVT_EDID_CVT3_SUPPORTED_RATE_60HZ :
270 rr = 60;
271 break;
272 case NVT_EDID_CVT3_SUPPORTED_RATE_85HZ :
273 rr = 85;
274 break;
275 case NVT_EDID_CVT3_SUPPORTED_RATE_75HZ :
276 rr = 75;
277 break;
278 case NVT_EDID_CVT3_SUPPORTED_RATE_50HZ :
279 rr = 50;
280 break;
281 }
282
283 NVMISC_MEMSET(&newTiming, 0, sizeof(newTiming));
284
285 if ( (k) != NVT_EDID_CVT3_SUPPORTED_RATE_60HZ_REDUCED_BLANKING) // standard blanking
286 {
287 status = NvTiming_CalcCVT(width, height, rr,
288 NVT_PROGRESSIVE,
289 &newTiming);
290 }
291 else // reduced blanking
292 {
293 status = NvTiming_CalcCVT_RB(width, height, rr,
294 NVT_PROGRESSIVE,
295 &newTiming);
296 }
297
298 if (status == NVT_STATUS_SUCCESS)
299 {
300 // For VTB timings, add additional information
301 if (vtbCount)
302 {
303 (*vtbCount)++;
304 newTiming.etc.status = NVT_STATUS_EDID_VTB_EXT_CVTn(*vtbCount);
305 newTiming.etc.name[39] = '\0';
306 }
307
308 if (!assignNextAvailableTiming(pInfo, &newTiming))
309 {
310 break;
311 }
312 }
313 } // for (k=1; k<=0x10; k<<=1)
314
315 }
316
317 // parse the EDID 1.x based cvt timing info
CODE_SEGMENT(PAGE_DD_CODE)318 CODE_SEGMENT(PAGE_DD_CODE)
319 void parseEdidCvtTiming(NVT_EDID_INFO *pInfo)
320 {
321 NvU32 i, j;
322
323 // find display range limit with cvt, or cvt 3-byte LDDs
324 for (i=0; i<NVT_EDID_MAX_LONG_DISPLAY_DESCRIPTOR; i++)
325 {
326 if ( pInfo->ldd[i].tag == NVT_EDID_DISPLAY_DESCRIPTOR_CVT )
327 {
328 NVT_EDID_DD_CVT_3BYTE *pCVT = (NVT_EDID_DD_CVT_3BYTE *)&pInfo->ldd[i].u.cvt;
329
330 // loop through cvt 3-byte blocks
331 for (j=0; j<NVT_EDID_DD_MAX_CVT3_PER_DESCRITPOR; j++)
332 {
333 parseEdidCvt3ByteDescriptor((NvU8 *)(pCVT->block + j),
334 pInfo, NULL);
335 } // for(j=0; j<NVT_EDID_DD_CVT3_BLOCK_NUM; j++)
336 } // else if CVT 3-byte block
337 } // for (i=0; i<NVT_EDID_MAX_LONG_DISPLAY_DESCRIPTOR; i++)
338 }
339
340 // parse the EDID 1.x based established timing info
CODE_SEGMENT(PAGE_DD_CODE)341 CODE_SEGMENT(PAGE_DD_CODE)
342 void parseEdidEstablishedTiming(NVT_EDID_INFO *pInfo)
343 {
344 NvU32 i, j, k;
345 NvU32 count = 0;
346 NVT_TIMING newTiming;
347
348 for (i = 1 << (sizeof(pInfo->established_timings_1_2) * 8 - 1), j = 0; i != 0; i >>= 1, j ++)
349 {
350 if ((pInfo->established_timings_1_2 & i) != 0 && EDID_EST[j].pclk != 0)
351 {
352 // count the timing
353 newTiming = EDID_EST[j];
354 newTiming.etc.status = NVT_STATUS_EDID_ESTn(++count);
355 NVT_SNPRINTF((char *)newTiming.etc.name, 40,
356 "EDID-EST(VESA):%dx%dx%dHz",
357 (int)newTiming.HVisible,
358 (int)newTiming.VVisible,
359 (int)newTiming.etc.rr);
360 newTiming.etc.name[39] = '\0';
361
362 if (!assignNextAvailableTiming(pInfo, &newTiming))
363 {
364 break;
365 }
366 }
367 }
368
369 // ESTIII block in ldd only supported in EDID1.4 and above
370 if (pInfo->version < NVT_EDID_VER_1_4)
371 return;
372
373 for (i=0; i<NVT_EDID_MAX_LONG_DISPLAY_DESCRIPTOR; i++)
374 {
375 if ( pInfo->ldd[i].tag == NVT_EDID_DISPLAY_DESCRIPTOR_ESTIII )
376 {
377 NVT_EDID_DD_EST_TIMING3* pEST = &pInfo->ldd[i].u.est3;
378
379 for (j=0; j<NVT_EDID_DD_EST_TIMING3_NUM; j++) // loop through each byte
380 {
381 // loop through each bit in the byte
382 for (k=7; k<=7; k--)
383 {
384 // find if the bit is 1 and we have a valid associated timing
385 if (pEST->data[j] & (1<<k) && EDID_ESTIII[(j*8)+(7-k)].pclk != 0)
386 {
387 newTiming = EDID_ESTIII[(j*8)+(7-k)];
388 newTiming.etc.status = NVT_STATUS_EDID_ESTn(++count);
389 NVT_SNPRINTF((char *)newTiming.etc.name, 40,
390 "EDID-EST(III):%dx%dx%dHz",
391 (int)newTiming.HVisible,
392 (int)newTiming.VVisible,
393 (int)newTiming.etc.rr);
394 newTiming.etc.name[39] = '\0';
395
396 if (!assignNextAvailableTiming(pInfo, &newTiming))
397 {
398 break;
399 }
400 }
401 }
402 }
403 break;
404 }
405 }
406 }
407
CODE_SEGMENT(PAGE_DD_CODE)408 CODE_SEGMENT(PAGE_DD_CODE)
409 void parseEdidStandardTimingDescriptor(NvU16 timing, NVT_EDID_INFO *pInfo, NvU32 count, NVT_TIMING * pT)
410 {
411 NvU32 aspect, width, height, rr;
412 count++;
413
414 // The value in the EDID = (Horizontal active pixels/8) - 31
415 width = (timing & 0x0FF) + 31;
416 width <<= 3;
417 rr = ((timing >> 8) & 0x3F) + 60; // bits 5->0
418
419 // get the height
420 aspect = ((timing >> 8) & 0xC0); // aspect ratio at bit 7:6
421 if (aspect == 0x00)
422 height = (pInfo->version < 0x103) ? width : (width * 5 / 8); //16:10 per EDID1.3 and 1:1 with earlier EDID
423 else if (aspect == 0x40)
424 height = width * 3 / 4; //4:3
425 else if (aspect == 0x80)
426 height = width * 4 / 5; //5:4
427 else
428 height = width * 9 / 16; //16:9
429
430 // try to get the timing from DMT first
431 if (NvTiming_CalcDMT(width, height, rr, 0, pT) == NVT_STATUS_SUCCESS)
432 {
433 pT->etc.status = NVT_STATUS_EDID_STDn(count);
434 NVT_SNPRINTF((char *)pT->etc.name, 40, "EDID-STD(DMT):%dx%dx%dHz", (int)width, (int)height, (int)rr);
435 pT->etc.name[39] = '\0';
436 }
437 // EDID1.4 and above defaults to CVT, instead of GTF. GTF is deprecated as of 1.4.
438 else if ((pInfo->version >= NVT_EDID_VER_1_4) && (NvTiming_CalcCVT(width, height, rr, NVT_PROGRESSIVE, pT) == NVT_STATUS_SUCCESS))
439 {
440 pT->etc.status = NVT_STATUS_EDID_STDn(count);
441 NVT_SNPRINTF((char *)pT->etc.name, 40, "EDID-STD(CVT):%dx%dx%dHz", (int)width, (int)height, (int)rr);
442 pT->etc.name[39] = '\0';
443 }
444 else
445 {
446 // if the mode is not found in DMT, use GTF timing
447 if (NvTiming_CalcGTF(width, height, rr, NVT_PROGRESSIVE, pT) == NVT_STATUS_SUCCESS)
448 {
449 NVT_SNPRINTF((char *)pT->etc.name, 40, "EDID-STD(GTF):%dx%dx%dHz", (int)width, (int)height, (int)rr);
450 pT->etc.name[39] = '\0';
451 }
452 pT->etc.status = NVT_STATUS_EDID_STDn(count);
453 }
454 }
455
456 // parse the EDID 1.x based standard timing info
CODE_SEGMENT(PAGE_DD_CODE)457 CODE_SEGMENT(PAGE_DD_CODE)
458 void parseEdidStandardTiming(NVT_EDID_INFO *pInfo)
459 {
460 NvU32 i, j;
461 NVT_TIMING newTiming;
462 NvU32 count = 0;
463
464 // now check for standard timings
465 for (i=0; i<NVT_EDID_MAX_STANDARD_TIMINGS; i++)
466 {
467 if (((pInfo->standard_timings[i] & 0x0FF) != 0x1) && //proper indication of unused field
468 (pInfo->standard_timings[i] != 0x0)) //improper indication (bad edid)
469 {
470 NVMISC_MEMSET(&newTiming, 0, sizeof(newTiming));
471
472 parseEdidStandardTimingDescriptor(pInfo->standard_timings[i],
473 pInfo, count, &newTiming);
474
475 if (!assignNextAvailableTiming(pInfo, &newTiming))
476 {
477 break;
478 }
479
480 count++;
481 }//if ((pInfo->standard_timings[i] & 0x0FF) != 0x1)
482 } //for (i=0; i<NVT_EDID_MAX_STANDARD_TIMINGS; i++)
483
484 // STI block in ldd only supported in EDID1.4 and above
485 if (pInfo->version < NVT_EDID_VER_1_4)
486 return;
487
488 // now check for standard timings in long display descriptors
489 for (i=0; i<NVT_EDID_MAX_LONG_DISPLAY_DESCRIPTOR; i++)
490 {
491 if ( pInfo->ldd[i].tag == NVT_EDID_DISPLAY_DESCRIPTOR_STI )
492 {
493 NVT_EDID_DD_STD_TIMING* pSTI = &pInfo->ldd[i].u.std_timing;
494 for (j=0; j<NVT_EDID_DD_STI_NUM; j++)
495 {
496 if ((pSTI->descriptor[j] & 0x0FF) != 0x00)
497 {
498 NVMISC_MEMSET(&newTiming, 0, sizeof(newTiming));
499
500 parseEdidStandardTimingDescriptor(pSTI->descriptor[j],
501 pInfo, count, &newTiming);
502
503 if (!assignNextAvailableTiming(pInfo, &newTiming))
504 {
505 break;
506 }
507
508 count++;
509 } // if ((pSTI->std_timing[i] & 0x0FF) != 0x1)
510 } //for (j=0; j<NVT_EDID_DD_STI_NUM; j++)
511 } //if ( ((EDID_LONG_DISPLAY_DESCRIPTOR)p->DetailedTimingDesc[i]).tag = NVT_EDID_DISPLAY_DESCRIPTOR_STI )
512 } //for (i=0; i<NVT_EDID_MAX_LONG_DISPLAY_DESCRIPTOR; i++)
513 }
514
515 // parse the signal detailed timing descriptor
CODE_SEGMENT(PAGE_DD_CODE)516 CODE_SEGMENT(PAGE_DD_CODE)
517 NVT_STATUS parseEdidDetailedTimingDescriptor(NvU8 *p, NVT_TIMING *pT)
518 {
519 DETAILEDTIMINGDESCRIPTOR *pDTD = (DETAILEDTIMINGDESCRIPTOR *)p;
520 NvU32 dwTotalPixels;
521 NvS32 hvisible, vvisible;
522
523 // bypass input parameter check in the private function
524
525
526 // For EDID ver 1.1 & 1.2:
527 // All bytes filled with 1 are considered as an empty block and should be skipped.
528 // Here we just check first 5 bytes.
529 // Release 5th byte zero check. Now we only check first 4 bytes. Some buggy EDID has
530 // data in 5th byte.
531 if(pDTD && (pDTD->wDTPixelClock !=0 || pDTD->bDTHorizontalActive !=0)
532 && (pDTD->wDTPixelClock != 0x0101 || pDTD->bDTHorizontalActive != 1 ||
533 pDTD->bDTHorizontalBlanking != 1 || pDTD->bDTHorizActiveBlank != 1))
534 {
535 // Note that hvisible and vvisible here correspond to the "Addressable Video" portion of the
536 // "Active Video" defined in the EDID spec (see section 3.12: Note Regarding Borders)
537 hvisible = (pDTD->bDTHorizontalActive + ((pDTD->bDTHorizActiveBlank & 0xF0) << 4)) - 2 * pDTD->bDTHorizontalBorder;
538 vvisible = (pDTD->bDTVerticalActive + ((pDTD->bDTVertActiveBlank & 0xF0) << 4)) - 2 * pDTD->bDTVerticalBorder;
539
540 // Sanity check since we are getting values from the monitor
541 if (hvisible <= 0 || vvisible <= 0 || pDTD->wDTPixelClock == 0)
542 {
543 if (pT)
544 pT->HVisible = 0;
545 return NVT_STATUS_ERR;
546 }
547
548 // if the output timing buffer is not provide, simply return here to indicate a legal descriptor
549 if (pT == NULL)
550 return NVT_STATUS_SUCCESS;
551
552 // horizontal timing parameters
553 pT->HVisible = (NvU16)hvisible;
554 pT->HBorder = (NvU16)pDTD->bDTHorizontalBorder;
555 pT->HTotal = (NvU16)hvisible + (NvU16)(pDTD->bDTHorizontalBlanking + ((pDTD->bDTHorizActiveBlank & 0x0F) << 8)) + pT->HBorder * 2;
556 pT->HFrontPorch = (NvU16)(pDTD->bDTHorizontalSync + ((pDTD->bDTHorizVertSyncOverFlow & 0xC0) << 2));
557 pT->HSyncWidth = (NvU16)(pDTD->bDTHorizontalSyncWidth + ((pDTD->bDTHorizVertSyncOverFlow & 0x30) << 4));
558
559 // vertical timing parameters
560 pT->VVisible = (NvU16)vvisible;
561 pT->VBorder = (NvU16)pDTD->bDTVerticalBorder;
562 pT->VTotal = (NvU16)vvisible + (NvU16)(pDTD->bDTVerticalBlanking + ((pDTD->bDTVertActiveBlank & 0x0F) << 8)) + pT->VBorder * 2;
563 pT->VFrontPorch = (NvU16)(((pDTD->bDTVerticalSync & 0xF0) >> 4) + ((pDTD->bDTHorizVertSyncOverFlow & 0x0C) << 2));
564 pT->VSyncWidth = (NvU16)((pDTD->bDTVerticalSync & 0x0F) + ((pDTD->bDTHorizVertSyncOverFlow & 0x03) << 4));
565
566 // pixel clock
567 pT->pclk = (NvU32)pDTD->wDTPixelClock;
568
569 // sync polarities
570 if ((pDTD->bDTFlags & 0x18) == 0x18)
571 {
572 pT->HSyncPol = ((pDTD->bDTFlags & 0x2) != 0) ? NVT_H_SYNC_POSITIVE : NVT_H_SYNC_NEGATIVE;
573 pT->VSyncPol = ((pDTD->bDTFlags & 0x4) != 0) ? NVT_V_SYNC_POSITIVE : NVT_V_SYNC_NEGATIVE;
574 }
575 else if ((pDTD->bDTFlags & 0x18) == 0x10)
576 {
577 pT->HSyncPol = ((pDTD->bDTFlags & 0x2) != 0) ? NVT_H_SYNC_POSITIVE : NVT_H_SYNC_NEGATIVE;
578 pT->VSyncPol = NVT_V_SYNC_POSITIVE;
579 }
580 else
581 {
582 pT->HSyncPol = NVT_H_SYNC_NEGATIVE;
583 pT->VSyncPol = NVT_V_SYNC_POSITIVE;
584 }
585
586 // interlaced
587 if ((pDTD->bDTFlags & 0x80) == 0x80)
588 pT->interlaced = 1;
589 else
590 pT->interlaced = 0;
591
592 // Eizo split EDID case, using 0th bit to indicate split display capability
593 if (((pDTD->bDTFlags & 1) == 1) && !(((pDTD->bDTFlags & 0x20) == 0x20) || ((pDTD->bDTFlags & 0x40) == 0x40)))
594 {
595 pT->etc.flag |= NVT_FLAG_EDID_DTD_EIZO_SPLIT;
596 }
597 if (pT->interlaced)
598 {
599 // Adjust for one extra blank line in every other frame.
600 dwTotalPixels = (((NvU32)pT->HTotal * pT->VTotal) +
601 ((NvU32)pT->HTotal * (pT->VTotal + 1))) / 2;
602 }
603 else
604 {
605 dwTotalPixels = (NvU32)pT->HTotal * pT->VTotal;
606 }
607
608 pT->etc.rr = (NvU16)(((NvU32)pDTD->wDTPixelClock*10000+dwTotalPixels/2)/dwTotalPixels);
609 // Using utility call to multiply and divide to take care of overflow and truncation of large values
610 // How did we arrive at 10000000? It comes from the fact that Pixel clock mentioned in EDID is in mulitples of 10KHz = 10000
611 // and the refresh rate is mentioned in 0.001Hz, that is 60Hz will be represented as 60000, which brings in the factor of 1000.
612 // And hence 10000 * 1000 = 10000000
613 pT->etc.rrx1k = axb_div_c(pDTD->wDTPixelClock, 10000000, dwTotalPixels);
614 pT->etc.status = NVT_STATUS_EDID_DTD;
615 NVT_SNPRINTF((char *)pT->etc.name, sizeof(pT->etc.name), "EDID-Detailed:%dx%dx%d.%03dHz%s", (int)pT->HVisible, (int)(pT->interlaced ? 2 : 1)*pT->VVisible , (int)pT->etc.rrx1k/1000, (int)pT->etc.rrx1k%1000, (pT->interlaced ? "/i" : ""));
616 pT->etc.name[sizeof(pT->etc.name) - 1] = '\0';
617
618 // aspect ratio
619 pT->etc.aspect = (pDTD->bDTHorizVertImage & 0xF0) << 20 | pDTD->bDTHorizontalImage << 16 |
620 (pDTD->bDTHorizVertImage & 0x0F) << 8 | pDTD->bDTVerticalImage;
621
622 pT->etc.rep = 0x1; // Bit mask for no pixel repetition.
623
624 return NVT_STATUS_SUCCESS;
625 }
626
627 return NVT_STATUS_ERR;
628 }
629
630 // parse the EDID 1.x based standard timing info
CODE_SEGMENT(PAGE_DD_CODE)631 CODE_SEGMENT(PAGE_DD_CODE)
632 void parseEdidDetailedTiming(NvU8 *pEdid, NVT_EDID_INFO *pInfo)
633 {
634 EDIDV1STRUC *p = (EDIDV1STRUC *) pEdid;
635 NVT_TIMING newTiming;
636 NvU32 i;
637 NvBool found = NV_FALSE;
638
639 for (i = 0; i < 4; i++)
640 {
641 NVMISC_MEMSET(&newTiming, 0, sizeof(newTiming));
642
643 if (parseEdidDetailedTimingDescriptor((NvU8 *)&p->DetailedTimingDesc[i],
644 &newTiming) == NVT_STATUS_SUCCESS)
645 {
646 newTiming.etc.status = NVT_STATUS_EDID_DTDn(i+1);
647
648 if (!assignNextAvailableTiming(pInfo, &newTiming))
649 {
650 break;
651 }
652
653 found = NV_TRUE;
654 }
655 }
656
657 if (found)
658 {
659 // if edid_ver 1.3, PTM flag should be set
660 //nvt_assert(pInfo->version > 0x103 || (pInfo->u.feature &
661 // NVT_EDID_OTHER_FEATURES_PTM_INCLUDE_NATIVE));
662
663 if (pInfo->u.feature & NVT_EDID_OTHER_FEATURES_PTM_INCLUDE_NATIVE)
664 {
665 pInfo->timing[0].etc.flag |= NVT_FLAG_DTD1_PREFERRED_TIMING;
666 }
667 }
668 }
669
670
671 // parse the EDID 1.x 18-byte long display descriptor
CODE_SEGMENT(PAGE_DD_CODE)672 CODE_SEGMENT(PAGE_DD_CODE)
673 static void parseEdidLongDisplayDescriptor(EDID_LONG_DISPLAY_DESCRIPTOR *descriptor, NVT_EDID_18BYTE_DESCRIPTOR *p, NvU32 version)
674 {
675 NvU32 i;
676
677 // bypass the input pointer check in this private function
678
679 // return if it's a detailed timing descriptor
680 if (descriptor->prefix[0] != 0 || descriptor->prefix[1] != 0)
681 return;
682
683 // other sanity check for the input data
684 if (descriptor->rsvd != 0)
685 return;
686
687 p->tag = descriptor->tag;
688
689 // now translate the descriptor
690 switch (descriptor->tag)
691 {
692 case NVT_EDID_DISPLAY_DESCRIPTOR_DPSN: // display product serial number
693 case NVT_EDID_DISPLAY_DESCRITPOR_DPN: // display product name
694 case NVT_EDID_DISPLAY_DESCRIPTOR_ADS: // alphanumeric data string (ASCII)
695
696 // copy the 13 characters payload from the 18-byte descriptor
697 for (i = 0; i < NVT_PVT_EDID_LDD_PAYLOAD_SIZE; i++)
698 {
699 if (descriptor->data[i] == 0x0A)
700 p->u.serial_number.str[i] = '\0';
701 else
702 p->u.serial_number.str[i] = descriptor->data[i];
703 }
704 break;
705
706 case NVT_EDID_DISPLAY_DESCRIPTOR_DRL: // display range limit
707 {
708 EDID_MONITOR_RANGE_LIMIT *pRangeLimit = (EDID_MONITOR_RANGE_LIMIT *)&descriptor->data[0];
709
710 p->u.range_limit.min_v_rate = pRangeLimit->minVRate;
711 p->u.range_limit.max_v_rate = pRangeLimit->maxVRate;
712 p->u.range_limit.min_h_rate = pRangeLimit->minHRate;
713 p->u.range_limit.max_h_rate = pRangeLimit->maxHRate;
714 p->u.range_limit.max_pclk_MHz = pRangeLimit->maxPClock10M * 10;
715 p->u.range_limit.timing_support = pRangeLimit->timing_support;
716
717 // add 255Hz offsets if needed, use descriptor->rsvd2
718 // to offset the min values their max MUST be offset as well
719 if (version >= NVT_EDID_VER_1_4)
720 {
721 if (descriptor->rsvd2 & NVT_PVT_EDID_RANGE_OFFSET_VER_MAX)
722 {
723 p->u.range_limit.max_v_rate += NVT_PVT_EDID_RANGE_OFFSET_AMOUNT;
724 if (descriptor->rsvd2 & NVT_PVT_EDID_RANGE_OFFSET_VER_MIN)
725 {
726 p->u.range_limit.min_v_rate += NVT_PVT_EDID_RANGE_OFFSET_AMOUNT;
727 }
728 }
729 if (descriptor->rsvd2 & NVT_PVT_EDID_RANGE_OFFSET_HOR_MAX)
730 {
731 p->u.range_limit.max_h_rate += NVT_PVT_EDID_RANGE_OFFSET_AMOUNT;
732 if (descriptor->rsvd2 & NVT_PVT_EDID_RANGE_OFFSET_HOR_MIN)
733 {
734 p->u.range_limit.min_h_rate += NVT_PVT_EDID_RANGE_OFFSET_AMOUNT;
735 }
736 }
737 }
738
739 if (p->u.range_limit.timing_support == NVT_EDID_RANGE_SUPPORT_GTF2)
740 {
741 // descriptor->data[7]
742 // Start frequency for secondary curve, hor freq./2[kHz]
743 p->u.range_limit.u.gtf2.C = pRangeLimit->u.gtf2.C / 2; // 0 <= C <= 127
744 p->u.range_limit.u.gtf2.K = pRangeLimit->u.gtf2.K; // 0 <= K <= 255
745 p->u.range_limit.u.gtf2.J = pRangeLimit->u.gtf2.J / 2; // 0 <= J <= 127
746 p->u.range_limit.u.gtf2.M = (pRangeLimit->u.gtf2.M_MSB << 8)
747 + pRangeLimit->u.gtf2.M_LSB; // 0 <= M <= 65535
748 }
749 else if (p->u.range_limit.timing_support == NVT_EDID_RANGE_SUPPORT_CVT)
750 {
751 // the pixel clock adjustment is in cvt.pixel_clock @ bits7:2
752 // that number is in 0.25MHz, ie actual max clock is max_pclk_MHz - (0.25 x cvt_pixel_clock)
753 // subtract the whole number part from max_pclk_MHz, save the remainder
754 p->u.range_limit.max_pclk_MHz -= (pRangeLimit->u.cvt.pixel_clock & NVT_PVT_EDID_CVT_PIXEL_CLOCK_MASK) >> NVT_PVT_EDID_CVT_PIXEL_CLOCK_SHIFT >> 2; // ie divide by 4 to get whole number
755 p->u.range_limit.u.cvt.pixel_clock_adjustment = ((pRangeLimit->u.cvt.pixel_clock & NVT_PVT_EDID_CVT_PIXEL_CLOCK_MASK) >> NVT_PVT_EDID_CVT_PIXEL_CLOCK_SHIFT) & 0x03; // ie modulus 4
756
757 p->u.range_limit.u.cvt.max_active_pixels_per_line = (pRangeLimit->u.cvt.pixel_clock & NVT_PVT_EDID_CVT_ACTIVE_MSB_MASK) << NVT_PVT_EDID_CVT_ACTIVE_MSB_SHIFT;
758 p->u.range_limit.u.cvt.max_active_pixels_per_line |= pRangeLimit->u.cvt.max_active;
759 p->u.range_limit.u.cvt.max_active_pixels_per_line <<= 3; // ie multiply 8
760
761 p->u.range_limit.u.cvt.aspect_supported = (pRangeLimit->u.cvt.aspect_supported & NVT_PVT_EDID_CVT_ASPECT_SUPPORTED_MASK) >> NVT_PVT_EDID_CVT_ASPECT_SUPPORTED_SHIFT;
762
763 p->u.range_limit.u.cvt.aspect_preferred = ( pRangeLimit->u.cvt.aspect_preferred_blanking & NVT_PVT_EDID_CVT_ASPECT_PREFERRED_MASK) >> NVT_PVT_EDID_CVT_ASPECT_PREFERRED_SHIFT;
764 p->u.range_limit.u.cvt.blanking_support = ( pRangeLimit->u.cvt.aspect_preferred_blanking & NVT_PVT_EDID_CVT_BLANKING_MASK) >> NVT_PVT_EDID_CVT_BLANKING_SHIFT;
765
766 p->u.range_limit.u.cvt.scaling_support = (pRangeLimit->u.cvt.scaling_support & NVT_PVT_EDID_CVT_SCALING_MASK) >> NVT_PVT_EDID_CVT_SCALING_SHIFT;
767
768 p->u.range_limit.u.cvt.preferred_refresh_rate = pRangeLimit->u.cvt.preferred_refresh_rate;
769 }
770 }
771
772 break;
773
774 case NVT_EDID_DISPLAY_DESCRIPTOR_CPD: // color point data
775 {
776 EDID_COLOR_POINT_DATA *pColorPoint = (EDID_COLOR_POINT_DATA *)&descriptor->data[0];
777
778 p->u.color_point.wp1_index = pColorPoint->wp1_index;
779 p->u.color_point.wp1_x = pColorPoint->wp1_x << 2;
780 p->u.color_point.wp1_x |= (pColorPoint->wp1_x_y & NVT_PVT_EDID_CPD_WP_X_MASK) >> NVT_PVT_EDID_CPD_WP_X_SHIFT;
781 p->u.color_point.wp1_y = pColorPoint->wp1_y << 2;
782 p->u.color_point.wp1_y |= (pColorPoint->wp1_x_y & NVT_PVT_EDID_CPD_WP_Y_MASK) >> NVT_PVT_EDID_CPD_WP_Y_SHIFT;
783 p->u.color_point.wp1_gamma = pColorPoint->wp1_gamma + 100;
784
785 p->u.color_point.wp2_index = pColorPoint->wp2_index;
786 p->u.color_point.wp2_x = pColorPoint->wp2_x << 2;
787 p->u.color_point.wp2_x |= (pColorPoint->wp2_x_y & NVT_PVT_EDID_CPD_WP_X_MASK) >> NVT_PVT_EDID_CPD_WP_X_SHIFT;
788 p->u.color_point.wp2_y = pColorPoint->wp2_y << 2;
789 p->u.color_point.wp2_y |= (pColorPoint->wp2_x_y & NVT_PVT_EDID_CPD_WP_Y_MASK) >> NVT_PVT_EDID_CPD_WP_Y_SHIFT;
790 p->u.color_point.wp2_gamma = pColorPoint->wp2_gamma + 100;
791 }
792 break;
793
794 case NVT_EDID_DISPLAY_DESCRIPTOR_STI: // standard timing identification
795 {
796 EDID_STANDARD_TIMING_ID *pStdTiming = (EDID_STANDARD_TIMING_ID *)&descriptor->data[0];
797
798 for(i=0; i<NVT_EDID_DD_STI_NUM; i++)
799 {
800 p->u.std_timing.descriptor[i] = pStdTiming->std_timing[i];
801 }
802 }
803 break;
804
805 case NVT_EDID_DISPLAY_DESCRIPTOR_DCM: // display color management
806 {
807 EDID_COLOR_MANAGEMENT_DATA *pColorMan = (EDID_COLOR_MANAGEMENT_DATA *)&descriptor->data[0];
808
809 p->u.color_man.red_a3 = pColorMan->red_a3_lsb | (pColorMan->red_a3_msb << 8);
810 p->u.color_man.red_a2 = pColorMan->red_a2_lsb | (pColorMan->red_a2_msb << 8);
811
812 p->u.color_man.green_a3 = pColorMan->green_a3_lsb | (pColorMan->green_a3_msb << 8);
813 p->u.color_man.green_a2 = pColorMan->green_a2_lsb | (pColorMan->green_a2_msb << 8);
814
815 p->u.color_man.blue_a3 = pColorMan->blue_a3_lsb | (pColorMan->blue_a3_msb << 8);
816 p->u.color_man.blue_a2 = pColorMan->blue_a2_lsb | (pColorMan->blue_a2_msb << 8);
817 }
818 break;
819
820 case NVT_EDID_DISPLAY_DESCRIPTOR_CVT: // CVT 3-byte timing code
821 {
822 EDID_CVT_3BYTE *pCVT_3byte = (EDID_CVT_3BYTE *)&descriptor->data[0];
823
824 for (i=0; i<NVT_EDID_DD_MAX_CVT3_PER_DESCRITPOR; i++)
825 {
826 if (pCVT_3byte->block[i].addressable_lines != 0)
827 {
828 p->u.cvt.block[i].addressable_lines = pCVT_3byte->block[i].addressable_lines;
829 p->u.cvt.block[i].addressable_lines |= (pCVT_3byte->block[i].lines_ratio & NVT_PVT_EDID_CVT3_LINES_MSB_MASK) << NVT_PVT_EDID_CVT3_LINES_MSB_SHIFT;
830 p->u.cvt.block[i].addressable_lines +=1;
831 p->u.cvt.block[i].addressable_lines <<= 1;
832
833 p->u.cvt.block[i].aspect_ratio = (pCVT_3byte->block[i].lines_ratio & NVT_PVT_EDID_CVT3_ASPECT_MASK) >> NVT_PVT_EDID_CVT3_ASPECT_SHIFT;
834
835 p->u.cvt.block[i].preferred_vert_rates = (pCVT_3byte->block[i].refresh_rates & NVT_PVT_EDID_CVT3_PREFERRED_RATE_MASK) >> NVT_PVT_EDID_CVT3_PREFERRED_RATE_SHIFT;
836 p->u.cvt.block[i].supported_vert_rates = (pCVT_3byte->block[i].refresh_rates & NVT_PVT_EDID_CVT3_SUPPORTED_RATE_MASK) >> NVT_PVT_EDID_CVT3_SUPPORTED_RATE_SHIFT;
837 }
838 }
839 }
840 break;
841
842 case NVT_EDID_DISPLAY_DESCRIPTOR_ESTIII: // establishied timing III
843 {
844 EDID_EST_TIMINGS_III *pEstTiming = (EDID_EST_TIMINGS_III *)&descriptor->data[0];
845
846 for(i=0; i<NVT_EDID_DD_EST_TIMING3_NUM; i++)
847 {
848 p->u.est3.data[i] = pEstTiming->timing_byte[i];
849 }
850 }
851 break;
852
853 case NVT_EDID_DISPLAY_DESCRIPTOR_DUMMY: // dummy descriptor
854 default:
855 // unresolved descriptor yet
856 for (i = 0; i < NVT_PVT_EDID_LDD_PAYLOAD_SIZE; i++)
857 {
858 p->u.dummy.data[i] = descriptor->data[i];
859 }
860 break;
861 }
862
863 }
864
865 // get generic EDID info
CODE_SEGMENT(PAGE_DD_CODE)866 CODE_SEGMENT(PAGE_DD_CODE)
867 NVT_STATUS NV_STDCALL NvTiming_ParseEDIDInfo(NvU8 *pEdid, NvU32 length, NVT_EDID_INFO *pInfo)
868 {
869 NvU32 i, j, k, data;
870 EDIDV1STRUC *p;
871 NvU8 *pExt;
872 NVT_EDID_CEA861_INFO *p861Info;
873
874 // parameter check
875 if (pEdid == NULL || length < 128 || pInfo == NULL)
876 {
877 return NVT_STATUS_ERR;
878 }
879
880 NVMISC_MEMSET(pInfo, 0, sizeof(NVT_EDID_INFO));
881
882 // get the EDID version
883 if (getEdidVersion(pEdid, &pInfo->version) == NVT_STATUS_ERR)
884 {
885 return NVT_STATUS_ERR;
886 }
887
888 p = (EDIDV1STRUC *) pEdid;
889
890 // get the IDs
891 pInfo->manuf_id = p->wIDManufName;
892 pInfo->product_id = p->wIDProductCode;
893
894 // translate the ID into manufacturer's name
895 pInfo->manuf_name[0] = 'A' + (NvU8)((pInfo->manuf_id & 0x007c) >> 2) - 1;
896 pInfo->manuf_name[1] = 'A' + (NvU8)((pInfo->manuf_id & 0x0003) << 3 | (pInfo->manuf_id & 0xe000) >> 13) - 1;
897 pInfo->manuf_name[2] = 'A' + (NvU8)((pInfo->manuf_id & 0x1f00) >> 8) - 1;
898 pInfo->manuf_name[3] = '\0';
899
900 // get serial number
901 pInfo->serial_number = p->dwIDSerialNumber;
902
903 // get the week and year
904 pInfo->week = p->bWeekManuf;
905 pInfo->year = p->bYearManuf + 1990;
906
907 // get the interface info
908 pInfo->input.isDigital = (p->bVideoInputDef & NVT_PVT_EDID_INPUT_ISDIGITAL_MASK) >> NVT_PVT_EDID_INPUT_ISDIGITAL_SHIFT;
909
910 if (pInfo->input.isDigital && pInfo->version > 0x103) // must be at least EDID1.4 to support the following fields
911 {
912 switch ( (p->bVideoInputDef & NVT_PVT_EDID_INPUT_BPC_MASK) >> NVT_PVT_EDID_INPUT_BPC_SHIFT)
913 {
914 case NVT_PVT_EDID_INPUT_BPC_6 :
915 pInfo->input.u.digital.bpc = 6;
916 break;
917 case NVT_PVT_EDID_INPUT_BPC_8 :
918 pInfo->input.u.digital.bpc = 8;
919 break;
920 case NVT_PVT_EDID_INPUT_BPC_10 :
921 pInfo->input.u.digital.bpc = 10;
922 break;
923 case NVT_PVT_EDID_INPUT_BPC_12 :
924 pInfo->input.u.digital.bpc = 12;
925 break;
926 case NVT_PVT_EDID_INPUT_BPC_14 :
927 pInfo->input.u.digital.bpc = 14;
928 break;
929 case NVT_PVT_EDID_INPUT_BPC_16 :
930 pInfo->input.u.digital.bpc = 16;
931 break;
932 default :
933 pInfo->input.u.digital.bpc = 0;
934 break;
935 }
936 pInfo->input.u.digital.video_interface = (p->bVideoInputDef & NVT_PVT_EDID_INPUT_INTERFACE_MASK) >> NVT_PVT_EDID_INPUT_INTERFACE_SHIFT;
937 }
938 else if (!pInfo->input.isDigital)
939 {
940 pInfo->input.u.analog_data = (p->bVideoInputDef & NVT_PVT_EDID_INPUT_ANALOG_ETC_MASK) >> NVT_PVT_EDID_INPUT_ANALOG_ETC_SHIFT;
941 }
942
943 // get the max image size and aspect ratio
944 if (p->bMaxHorizImageSize != 0 && p->bMaxVertImageSize != 0)
945 {
946 pInfo->screen_size_x = p->bMaxHorizImageSize;
947 pInfo->screen_size_y = p->bMaxVertImageSize;
948 pInfo->screen_aspect_x = 0;
949 pInfo->screen_aspect_y = 0;
950 }
951 else if (p->bMaxHorizImageSize != 0 && p->bMaxVertImageSize == 0)
952 {
953 pInfo->screen_size_x = 0;
954 pInfo->screen_size_y = 0;
955 pInfo->screen_aspect_x = 99 + p->bMaxHorizImageSize;
956 pInfo->screen_aspect_y = 100;
957 }
958 else if (p->bMaxHorizImageSize == 0 && p->bMaxVertImageSize != 0)
959 {
960 pInfo->screen_size_x = 0;
961 pInfo->screen_size_y = 0;
962 pInfo->screen_aspect_x = 100;
963 pInfo->screen_aspect_y = 99 + p->bMaxVertImageSize;
964 }
965
966 // get the gamma
967 pInfo->gamma = p->bDisplayXferChar + 100;
968
969 // get the features
970 pInfo->u.feature = p->bFeatureSupport;
971
972 // get chromaticity coordinates
973 pInfo->cc_red_x = p->Chromaticity[2] << 2;
974 pInfo->cc_red_x |= (p->Chromaticity[0] & NVT_PVT_EDID_CC_RED_X1_X0_MASK) >> NVT_PVT_EDID_CC_RED_X1_X0_SHIFT;
975 pInfo->cc_red_y = p->Chromaticity[3] << 2;
976 pInfo->cc_red_y |= (p->Chromaticity[0] & NVT_PVT_EDID_CC_RED_Y1_Y0_MASK) >> NVT_PVT_EDID_CC_RED_Y1_Y0_SHIFT;
977
978 pInfo->cc_green_x = p->Chromaticity[4] << 2;
979 pInfo->cc_green_x |= (p->Chromaticity[0] & NVT_PVT_EDID_CC_GREEN_X1_X0_MASK) >> NVT_PVT_EDID_CC_GREEN_X1_X0_SHIFT;
980 pInfo->cc_green_y = p->Chromaticity[5] << 2;
981 pInfo->cc_green_y |= (p->Chromaticity[0] & NVT_PVT_EDID_CC_GREEN_Y1_Y0_MASK) >> NVT_PVT_EDID_CC_GREEN_Y1_Y0_SHIFT;
982
983 pInfo->cc_blue_x = p->Chromaticity[6] << 2;
984 pInfo->cc_blue_x |= (p->Chromaticity[1] & NVT_PVT_EDID_CC_BLUE_X1_X0_MASK) >> NVT_PVT_EDID_CC_BLUE_X1_X0_SHIFT;
985 pInfo->cc_blue_y = p->Chromaticity[7] << 2;
986 pInfo->cc_blue_y |= (p->Chromaticity[1] & NVT_PVT_EDID_CC_BLUE_Y1_Y0_MASK) >> NVT_PVT_EDID_CC_BLUE_Y1_Y0_SHIFT;
987
988 pInfo->cc_white_x = p->Chromaticity[8] << 2;
989 pInfo->cc_white_x |= (p->Chromaticity[1] & NVT_PVT_EDID_CC_WHITE_X1_X0_MASK) >> NVT_PVT_EDID_CC_WHITE_X1_X0_SHIFT;
990 pInfo->cc_white_y = p->Chromaticity[9] << 2;
991 pInfo->cc_white_y |= (p->Chromaticity[1] & NVT_PVT_EDID_CC_WHITE_Y1_Y0_MASK) >> NVT_PVT_EDID_CC_WHITE_Y1_Y0_SHIFT;
992
993 // copy established timings
994 pInfo->established_timings_1_2 = (NvU16)p->bEstablishedTimings1 << 8;
995 pInfo->established_timings_1_2 |= (NvU16)p->bEstablishedTimings2;
996
997 // copy manuf reserved timings
998 pInfo->manufReservedTimings = p->bManufReservedTimings;
999
1000 // copy standard timings
1001 for (i = 0; i < NVT_EDID_MAX_STANDARD_TIMINGS; i++)
1002 {
1003 pInfo->standard_timings[i] = p->wStandardTimingID[i];
1004 }
1005
1006 // get the number of extensions
1007 pInfo->total_extensions = p->bExtensionFlag;
1008
1009 // check_sum
1010 for (i = 0, data = 0; i < length; i++)
1011 {
1012 data += pEdid[i];
1013 }
1014 pInfo->checksum_ok = !(data & 0xFF);
1015 pInfo->checksum = p->bChecksum;
1016
1017
1018 // now find out the total number of all of the timings in the EDID
1019 pInfo->total_timings = 0;
1020
1021 // now find out the detailed timings
1022 parseEdidDetailedTiming(pEdid, pInfo);
1023
1024 // now parse all 18-byte long display descriptors (not detailed timing)
1025 for (i = 0; i < NVT_EDID_MAX_LONG_DISPLAY_DESCRIPTOR; i++)
1026 {
1027 parseEdidLongDisplayDescriptor((EDID_LONG_DISPLAY_DESCRIPTOR *)&p->DetailedTimingDesc[i], &pInfo->ldd[i], pInfo->version);
1028 }
1029
1030 // now check the number of timings in the extension
1031 for (k = 0, j = 1; j <= pInfo->total_extensions && (j + 1) * sizeof(EDIDV1STRUC) <= length; j++)
1032 {
1033 pExt = pEdid + sizeof(EDIDV1STRUC) * j;
1034
1035 // check for 861 extension first
1036 switch (*pExt)
1037 {
1038 case NVT_EDID_EXTENSION_CTA:
1039 p861Info = (k == 0) ? &pInfo->ext861 : &pInfo->ext861_2;
1040
1041 get861ExtInfo(pExt, sizeof(EDIDV1STRUC), p861Info);
1042
1043 // HF EEODB is present in edid v1.3 and v1.4 does not need this.Also, it is always present in the 1st CTA extension block.
1044 if (j == 1 && pInfo->version == NVT_EDID_VER_1_3)
1045 {
1046 parseCta861HfEeodb(p861Info, &pInfo->total_extensions);
1047 }
1048
1049 // update pInfo with basic hdmi info
1050 // assumes each edid will only have one such block across multiple cta861 blocks (otherwise may create declaration conflict)
1051 // In case of multiple such blocks, the last one takes precedence, except for SCDB
1052
1053 // parseCta861VsdbBlocks() uses hfScdb info so need to be parsed first
1054 parseCta861HfScdb(p861Info, pInfo, FROM_CTA861_EXTENSION);
1055 parseCta861VsdbBlocks(p861Info, pInfo, FROM_CTA861_EXTENSION);
1056 parseCta861VsvdbBlocks(p861Info, pInfo, FROM_CTA861_EXTENSION);
1057
1058 // parse HDR related information from the HDR static metadata data block
1059 parseCea861HdrStaticMetadataDataBlock(p861Info, pInfo, FROM_CTA861_EXTENSION);
1060
1061 // Timings are listed (or shall) be listed in priority order
1062 // So read SVD, yuv420 SVDs first before reading detailed timings
1063
1064 // add the 861B short video timing descriptor
1065 if (p861Info->revision >= NVT_CEA861_REV_B)
1066 {
1067 // base video
1068 parse861bShortTiming(p861Info, pInfo, FROM_CTA861_EXTENSION);
1069
1070 // yuv420-only video
1071 parse861bShortYuv420Timing(p861Info, pInfo, FROM_CTA861_EXTENSION);
1072 }
1073
1074 // add the detailed timings in 18-byte long display descriptor
1075 parse861ExtDetailedTiming(pExt, p861Info->basic_caps, pInfo);
1076
1077 if (p861Info->revision >= NVT_CTA861_REV_H)
1078 {
1079 if (p861Info->total_vfdb != 0) parseCta861VideoFormatDataBlock(p861Info, pInfo);
1080 if (p861Info->total_did_type7db != 0) parseCta861DIDType7VideoTimingDataBlock(p861Info, pInfo);
1081 if (p861Info->total_did_type8db != 0) parseCta861DIDType8VideoTimingDataBlock(p861Info, pInfo);
1082 if (p861Info->total_did_type10db != 0) parseCta861DIDType10VideoTimingDataBlock(p861Info, pInfo);
1083 }
1084
1085 // CEA861-F at 7.5.12 section about VFPDB block.
1086 if (p861Info->revision >= NVT_CEA861_REV_F && (p861Info->total_svr != 0 || p861Info->valid.NVRDB == 1))
1087 {
1088 parseCta861NativeOrPreferredTiming(p861Info, pInfo, FROM_CTA861_EXTENSION);
1089 }
1090
1091 k++;
1092 break;
1093
1094 case NVT_EDID_EXTENSION_VTB:
1095 parseVTBExtension(pExt, pInfo);
1096 break;
1097
1098 case NVT_EDID_EXTENSION_DISPLAYID:
1099 if ((pExt[1] & 0xF0) == 0x20) // displayID2.x as EDID extension
1100 {
1101 if(getDisplayId20EDIDExtInfo(pExt, sizeof(EDIDV1STRUC),
1102 pInfo) == NVT_STATUS_SUCCESS)
1103 {
1104 if (pInfo->ext861.total_y420vdb != 0 || pInfo->ext861.total_y420cmdb != 0)
1105 {
1106 pInfo->ext_displayid20.interface_features.yuv420_min_pclk = 0;
1107 }
1108
1109 if (pInfo->ext_displayid20.valid_data_blocks.interface_feature_present)
1110 {
1111 pInfo->ext861.basic_caps |= pInfo->ext_displayid20.basic_caps;
1112 }
1113 }
1114 }
1115 else // displayID13 as EDID extension
1116 {
1117 //do not fail function based on return value of getDisplayIdEDIDExtInfo refer bug 3247180 where some rogue monitors don't provide correct DID13 raw data.
1118 if (getDisplayIdEDIDExtInfo(pExt, sizeof(EDIDV1STRUC),
1119 pInfo) == NVT_STATUS_SUCCESS)
1120 {
1121 // Check if YCbCr is supported in base block
1122 // since it is mandatory if YCbCr is supported on any other display interface as per 5.1.1.1 Video Colorimetry
1123 if(pInfo->u.feature_ver_1_4_digital.support_ycrcb_444)
1124 {
1125 if (!pInfo->ext_displayid.supported_displayId2_0)
1126 {
1127 pInfo->ext_displayid.u4.display_interface.ycbcr444_depth.support_8b = 1;
1128 }
1129 else
1130 {
1131 pInfo->ext_displayid.u4.display_interface_features.ycbcr444_depth.support_8b = 1;
1132 }
1133 }
1134
1135 if(pInfo->u.feature_ver_1_4_digital.support_ycrcb_422)
1136 {
1137 if (!pInfo->ext_displayid.supported_displayId2_0)
1138 {
1139 pInfo->ext_displayid.u4.display_interface.ycbcr422_depth.support_8b = 1;
1140 }
1141 else
1142 {
1143 pInfo->ext_displayid.u4.display_interface_features.ycbcr422_depth.support_8b = 1;
1144 }
1145 }
1146 }
1147 }
1148 break;
1149
1150 default:
1151 break;
1152 }
1153 }
1154
1155 // Copy all the timings(could include type 7/8/9/10) from displayid20->timings[] to pEdidInfo->timings[]
1156 for (i = 0; i < pInfo->ext_displayid20.total_timings; i++)
1157 {
1158 if (!assignNextAvailableTiming(pInfo, &(pInfo->ext_displayid20.timing[i])))
1159 {
1160 return NVT_STATUS_ERR;
1161 }
1162 }
1163
1164 // check for cvt timings - in display range limits or cvt 3-byte LDD, only for EDID1.4 and above
1165 if (pInfo->version > NVT_EDID_VER_1_3)
1166 {
1167 parseEdidCvtTiming(pInfo);
1168 }
1169
1170 // now check for standard timings - base EDID and then the LDDs
1171 parseEdidStandardTiming(pInfo);
1172
1173 // find out the total established timings - base EDID and then the LDDs
1174 parseEdidEstablishedTiming(pInfo);
1175
1176 // remove the T8VTDB timing if it co-existed in standard or established timings
1177 if (pInfo->ext861.revision >= NVT_CTA861_REV_H && pInfo->ext861.total_did_type8db != 0 && pInfo->total_timings > 1)
1178 {
1179 for (i = 0; i < pInfo->total_timings; i++)
1180 {
1181 if (NVT_GET_TIMING_STATUS_TYPE(pInfo->timing[i].etc.status) == NVT_TYPE_CTA861_DID_T8)
1182 {
1183 if (isMatchedStandardTiming(pInfo, &pInfo->timing[i]) || isMatchedEstablishedTiming(pInfo, &pInfo->timing[i]))
1184 {
1185 for (j = i; j < pInfo->total_timings - 1; j++)
1186 {
1187 // remove the entry by moving the next entry up.
1188 pInfo->timing[j] = pInfo->timing[j+1];
1189 }
1190 NVMISC_MEMSET(&pInfo->timing[pInfo->total_timings-1], 0, sizeof(NVT_TIMING));
1191 pInfo->total_timings--; i--;
1192 }
1193 }
1194 }
1195 }
1196
1197 getEdidHDM1_4bVsdbTiming(pInfo);
1198
1199 // Assert if no timings were found (due to a bad EDID) or if we mistakenly
1200 // assigned more timings than we allocated space for (due to bad logic above)
1201 nvt_assert(pInfo->total_timings &&
1202 (pInfo->total_timings <= COUNT(pInfo->timing)));
1203
1204 // go through all timings and update supported color formats
1205 // consider the supported bpc per color format from parsed EDID / CTA861 / DisplayId
1206 updateColorFormatAndBpcTiming(pInfo);
1207
1208 return NVT_STATUS_SUCCESS;
1209 }
1210
CODE_SEGMENT(PAGE_DD_CODE)1211 CODE_SEGMENT(PAGE_DD_CODE)
1212 void updateColorFormatAndBpcTiming(NVT_EDID_INFO *pInfo)
1213 {
1214 NvU32 i, j, data;
1215
1216 for (i = 0; i < pInfo->total_timings; i++)
1217 {
1218 data = NVT_GET_TIMING_STATUS_TYPE(pInfo->timing[i].etc.status);
1219 switch (data)
1220 {
1221 case NVT_TYPE_HDMI_STEREO:
1222 case NVT_TYPE_HDMI_EXT:
1223 // VTB timing use the base EDID (block 0) to determine the color format support
1224 case NVT_TYPE_EDID_VTB_EXT:
1225 case NVT_TYPE_EDID_VTB_EXT_STD:
1226 case NVT_TYPE_EDID_VTB_EXT_DTD:
1227 case NVT_TYPE_EDID_VTB_EXT_CVT:
1228 // pInfo->u.feature_ver_1_3.color_type provides mono, rgb, rgy, undefined
1229 // assume RGB 8-bpc support only (VTB is pretty old edid standard)
1230 pInfo->timing[i].etc.rgb444.bpc.bpc8 = 1;
1231 break;
1232 // These are from the CTA block, and relies on
1233 // Since there could be multiple CEA blocks, these are adjusted when the blocks are parsed
1234 case NVT_TYPE_EDID_861ST:
1235 case NVT_TYPE_EDID_EXT_DTD:
1236 if (pInfo->ext_displayid20.as_edid_extension &&
1237 pInfo->ext_displayid20.valid_data_blocks.cta_data_present)
1238 {
1239 updateColorFormatForDisplayId20ExtnTimings(pInfo, i);
1240 }
1241 updateBpcForTiming(pInfo, i);
1242 break;
1243 default:
1244 // * the displayID_v1.3/v2.0 EDID extension need to follow the EDID bpc definition.
1245 // * all other default to base edid
1246 updateBpcForTiming(pInfo, i);
1247 }
1248
1249 // The timings[i] entries need to update the bpc values where are based on the different color format again
1250 // if displayId extension existed it's interface feature data block
1251 if (pInfo->ext_displayid.version == 0x12 || pInfo->ext_displayid.version == 0x13)
1252 {
1253 updateColorFormatForDisplayIdExtnTimings(pInfo, i);
1254 }
1255 else if (pInfo->ext_displayid20.valid_data_blocks.interface_feature_present)
1256 {
1257 // DisplayId2.0 spec has its own way of determining color format support which includes bpc + color format
1258 updateColorFormatForDisplayId20ExtnTimings(pInfo, i);
1259 }
1260 }
1261
1262 // Go through all the timings and set CTA format accordingly. If a timing is a CTA 861b timing, store the
1263 // index of this CTA 861b standard in NVT_TIMING.etc.status field.
1264 // However parser needs to exclude the DTD timing in EDID base block where is shared same detailed timing in VIC/DTD_ext in CTA861
1265 for (i = 0; i < pInfo->total_timings; i++)
1266 {
1267 data = NvTiming_GetCEA861TimingIndex(&pInfo->timing[i]);
1268 // DisplayID block did not belong to CTA timing and it owned the deep color block itself
1269 if (data && !((NVT_GET_TIMING_STATUS_TYPE(pInfo->timing[i].etc.status) == NVT_TYPE_DISPLAYID_1) ||
1270 (NVT_GET_TIMING_STATUS_TYPE(pInfo->timing[i].etc.status) == NVT_TYPE_DISPLAYID_2) ||
1271 (NVT_GET_TIMING_STATUS_TYPE(pInfo->timing[i].etc.status) == NVT_TYPE_DISPLAYID_7) ||
1272 (NVT_GET_TIMING_STATUS_TYPE(pInfo->timing[i].etc.status) == NVT_TYPE_DISPLAYID_8) ||
1273 (NVT_GET_TIMING_STATUS_TYPE(pInfo->timing[i].etc.status) == NVT_TYPE_DISPLAYID_9) ||
1274 (NVT_GET_TIMING_STATUS_TYPE(pInfo->timing[i].etc.status) == NVT_TYPE_DISPLAYID_10)))
1275 {
1276 // CEA timings may be enumerated outside of SVD blocks -- the formats of these timings don't have CEA FORMAT (vic) set
1277 // before marking them CEA, make sure their color formats are updated too
1278 if (NVT_GET_CEA_FORMAT(pInfo->timing[i].etc.status) == 0 &&
1279 (!NVT_IS_DTD(pInfo->timing[i].etc.status) ||
1280 isMatchedCTA861Timing(pInfo, &pInfo->timing[i])))
1281 {
1282 for (j = 0; j < pInfo->total_timings; j++)
1283 {
1284 // It is assumed CTA timings that are repeated by the CTA block or different CTA blocks will
1285 // announce the same color format for the same CTA timings
1286 if (NVT_GET_CEA_FORMAT(pInfo->timing[j].etc.status) == data)
1287 {
1288 // There could be anomalies between EDID 1.4 base block color format vs CEA861 basic caps
1289 // In this case we assume the union is supported
1290 pInfo->timing[i].etc.rgb444.bpcs |= pInfo->timing[j].etc.rgb444.bpcs;
1291 pInfo->timing[i].etc.yuv444.bpcs |= pInfo->timing[j].etc.yuv444.bpcs;
1292 pInfo->timing[i].etc.yuv422.bpcs |= pInfo->timing[j].etc.yuv422.bpcs;
1293 pInfo->timing[i].etc.yuv420.bpcs |= pInfo->timing[j].etc.yuv420.bpcs;
1294 break;
1295 }
1296 }
1297
1298 // now update the VIC of this timing
1299 NVT_SET_CEA_FORMAT(pInfo->timing[i].etc.status, data);
1300 }
1301 // see the aspect ratio info if needed
1302 if (pInfo->timing[i].etc.aspect == 0)
1303 {
1304 pInfo->timing[i].etc.aspect = getCEA861TimingAspectRatio(data);
1305 }
1306 }
1307 }
1308 }
1309
CODE_SEGMENT(PAGE_DD_CODE)1310 CODE_SEGMENT(PAGE_DD_CODE)
1311 NvBool isMatchedStandardTiming(NVT_EDID_INFO *pInfo, NVT_TIMING *pT)
1312 {
1313 NvU32 j;
1314
1315 for (j = 0; j < pInfo->total_timings; j++)
1316 {
1317 if (NVT_GET_TIMING_STATUS_TYPE(pInfo->timing[j].etc.status) == NVT_TYPE_EDID_STD &&
1318 NvTiming_IsTimingRelaxedEqual(&pInfo->timing[j], pT))
1319 {
1320 return NV_TRUE;
1321 }
1322 }
1323 return NV_FALSE;
1324 }
1325
CODE_SEGMENT(PAGE_DD_CODE)1326 CODE_SEGMENT(PAGE_DD_CODE)
1327 NvBool isMatchedEstablishedTiming(NVT_EDID_INFO *pInfo, NVT_TIMING *pT)
1328 {
1329 NvU32 j;
1330
1331 for (j = 0; j < pInfo->total_timings; j++)
1332 {
1333 if (NVT_GET_TIMING_STATUS_TYPE(pInfo->timing[j].etc.status) == NVT_TYPE_EDID_EST &&
1334 NvTiming_IsTimingRelaxedEqual(&pInfo->timing[j], pT))
1335 {
1336 return NV_TRUE;
1337 }
1338 }
1339 return NV_FALSE;
1340 }
1341
CODE_SEGMENT(PAGE_DD_CODE)1342 CODE_SEGMENT(PAGE_DD_CODE)
1343 NvBool isMatchedCTA861Timing(NVT_EDID_INFO *pInfo, NVT_TIMING *pT)
1344 {
1345 NvU32 j;
1346
1347 for (j = 0; j < pInfo->total_timings; j++)
1348 {
1349 if (NVT_GET_CEA_FORMAT(pInfo->timing[j].etc.status) && NvTiming_IsTimingExactEqual(&pInfo->timing[j], pT))
1350 {
1351 return NV_TRUE;
1352 }
1353 }
1354 return NV_FALSE;
1355 }
1356
CODE_SEGMENT(PAGE_DD_CODE)1357 CODE_SEGMENT(PAGE_DD_CODE)
1358 void updateBpcForTiming(NVT_EDID_INFO *pInfo, NvU32 index)
1359 {
1360 NVT_EDID_CEA861_INFO *p861Info;
1361
1362 // assume/prefer data from 1st CEA block if multiple exist
1363 p861Info = &pInfo->ext861;
1364
1365 pInfo->timing[index].etc.rgb444.bpc.bpc8 = 1;
1366
1367 if (pInfo->version >= NVT_EDID_VER_1_4 && pInfo->input.isDigital)
1368 {
1369 if (pInfo->u.feature_ver_1_4_digital.support_ycrcb_444)
1370 {
1371 pInfo->timing[index].etc.yuv444.bpc.bpc8 = 1;
1372 }
1373 if (pInfo->u.feature_ver_1_4_digital.support_ycrcb_422)
1374 {
1375 pInfo->timing[index].etc.yuv422.bpc.bpc8 = 1;
1376 }
1377 if (pInfo->input.u.digital.video_interface == NVT_EDID_DIGITAL_VIDEO_INTERFACE_STANDARD_DISPLAYPORT_SUPPORTED ||
1378 pInfo->input.u.digital.video_interface == NVT_EDID_DIGITAL_VIDEO_INTERFACE_STANDARD_UNDEFINED)
1379 {
1380 pInfo->timing[index].etc.rgb444.bpc.bpc6 = 1;
1381
1382 // trust bpc claim in edid base block for DP only
1383 if (pInfo->input.u.digital.bpc >= NVT_EDID_VIDEOSIGNAL_BPC_10)
1384 {
1385 pInfo->timing[index].etc.rgb444.bpc.bpc10 = 1;
1386 pInfo->timing[index].etc.yuv444.bpc.bpc10 = pInfo->u.feature_ver_1_4_digital.support_ycrcb_444 || (p861Info->basic_caps & NVT_CEA861_CAP_YCbCr_444);
1387 pInfo->timing[index].etc.yuv422.bpc.bpc10 = pInfo->u.feature_ver_1_4_digital.support_ycrcb_422 || (p861Info->basic_caps & NVT_CEA861_CAP_YCbCr_422);
1388 }
1389 if (pInfo->input.u.digital.bpc >= NVT_EDID_VIDEOSIGNAL_BPC_12)
1390 {
1391 pInfo->timing[index].etc.rgb444.bpc.bpc12 = 1;
1392 pInfo->timing[index].etc.yuv444.bpc.bpc12 = pInfo->u.feature_ver_1_4_digital.support_ycrcb_444 || (p861Info->basic_caps & NVT_CEA861_CAP_YCbCr_444);
1393 pInfo->timing[index].etc.yuv422.bpc.bpc12 = pInfo->u.feature_ver_1_4_digital.support_ycrcb_422 || (p861Info->basic_caps & NVT_CEA861_CAP_YCbCr_422);
1394 }
1395 if (pInfo->input.u.digital.bpc >= NVT_EDID_VIDEOSIGNAL_BPC_16)
1396 {
1397 pInfo->timing[index].etc.rgb444.bpc.bpc16 = 1;
1398 pInfo->timing[index].etc.yuv444.bpc.bpc16 = pInfo->u.feature_ver_1_4_digital.support_ycrcb_444 || (p861Info->basic_caps & NVT_CEA861_CAP_YCbCr_444);
1399 pInfo->timing[index].etc.yuv422.bpc.bpc16 = pInfo->u.feature_ver_1_4_digital.support_ycrcb_422 || (p861Info->basic_caps & NVT_CEA861_CAP_YCbCr_422);
1400 }
1401 }
1402 else if ((pInfo->input.u.digital.video_interface == NVT_EDID_DIGITAL_VIDEO_INTERFACE_STANDARD_HDMI_A_SUPPORTED ||
1403 pInfo->input.u.digital.video_interface == NVT_EDID_DIGITAL_VIDEO_INTERFACE_STANDARD_HDMI_B_SUPPORTED ||
1404 pInfo->input.u.digital.video_interface == NVT_EDID_DIGITAL_VIDEO_INTERFACE_STANDARD_UNDEFINED) &&
1405 p861Info->revision >= NVT_CEA861_REV_A)
1406 {
1407 updateHDMILLCDeepColorForTiming(pInfo, index);
1408 }
1409 }
1410 else if (p861Info->revision >= NVT_CEA861_REV_A)
1411 {
1412 updateHDMILLCDeepColorForTiming(pInfo, index);
1413 }
1414 }
1415
CODE_SEGMENT(PAGE_DD_CODE)1416 CODE_SEGMENT(PAGE_DD_CODE)
1417 NVT_STATUS NvTiming_Get18ByteLongDescriptorIndex(NVT_EDID_INFO *pEdidInfo, NvU8 tag, NvU32 *pDtdIndex)
1418 {
1419 NvU32 dtdIndex;
1420
1421 if (!pEdidInfo || !pDtdIndex)
1422 {
1423 return NVT_STATUS_ERR;
1424 }
1425
1426 for (dtdIndex = *pDtdIndex; dtdIndex < NVT_EDID_MAX_LONG_DISPLAY_DESCRIPTOR; dtdIndex++)
1427 {
1428 if (pEdidInfo->ldd[dtdIndex].tag == tag)
1429 {
1430 *pDtdIndex = dtdIndex;
1431 return NVT_STATUS_SUCCESS;
1432 }
1433 }
1434
1435 return NVT_STATUS_ERR;
1436 }
1437
1438 // get the edid timing
CODE_SEGMENT(PAGE_DD_CODE)1439 CODE_SEGMENT(PAGE_DD_CODE)
1440 NVT_STATUS NvTiming_GetEdidTimingExWithPclk(NvU32 width, NvU32 height, NvU32 rr, NvU32 flag, NVT_EDID_INFO *pEdidInfo, NVT_TIMING *pT, NvU32 rrx1k, NvU32 pclk)
1441 {
1442 NvU8 kth = 0;
1443 NvU32 i, j;
1444 NvU32 native_cta, preferred_cta, preferred_displayid_dtd, preferred_dtd1, dtd1, map0, map1, map2, map3, map4, ceaIndex, max, cvt;
1445 NVT_TIMING *pEdidTiming;
1446 NVT_EDID_DD_RANGE_CVT *pCVT = NULL;
1447 NVT_TIMING cvtTiming;
1448
1449 // input check
1450 if (pEdidInfo == NULL || pEdidInfo->total_timings == 0 || pT == 0)
1451 return NVT_STATUS_ERR;
1452
1453 if (width == 0 || height == 0 || rr == 0 ) // rrx1k and pclk are optional, can be 0.
1454 return NVT_STATUS_ERR;
1455
1456 pEdidTiming = pEdidInfo->timing;
1457
1458 // the timing mapping index :
1459 //
1460 // native_cta - the "native resoluiotn of the sink" in the CTA861.6 A Source shall override any other native video resolution indicators
1461 // if the Source supports NVRDB and the NVRDB was found in the E-EDID
1462 // preferred_cta - the "prefer SVD" in CTA-861-F (i.e. A Sink that prefers a Video Format that is not listed as an SVD in Video Data Block, but instead listed in YCBCR 4:2:0 VDB)
1463 // preferred_displayid_dtd - the "prefer detailed timing of DispalyID" extension
1464 // preferred_dtd1 - the first deatiled timing and PTM flag is enable
1465 // dtd1 - the first detailed timing
1466 // map0 - the "perfect" match (the timing's H/V-visible and pixel clock(refresh rate) are the same as the asking "width", "height" and "rr".
1467 // map1 - the "closest" match with the honor of the interlaced flag
1468 // map2 - the "closest" match without the honor of the interlaced flag
1469 // map3 - the "closest" match to the panel's native timing (i.e. the first DTD timing or the short 861B/C/D timings with "native" flag).
1470 // map4 - the "closest" match with the same refresh rate
1471 // max - the timing with the max visible area
1472 native_cta = preferred_cta = preferred_displayid_dtd = preferred_dtd1 = dtd1 = map0 = map1 = map2 = map3 = map4 = ceaIndex = pEdidInfo->total_timings;
1473 max = cvt = 0;
1474
1475 if (pEdidInfo->ext861.total_svr > 1)
1476 {
1477 kth = getHighestPrioritySVRIdx(&pEdidInfo->ext861);
1478 }
1479
1480 for (i = 0; i < pEdidInfo->total_timings; i++)
1481 {
1482 // if the client prefers _NATIVE timing, then don't select custom timing
1483 if ((flag & (NVT_FLAG_NATIVE_TIMING | NVT_FLAG_EDID_TIMING)) != 0 && NVT_IS_CUST_ENTRY(pEdidTiming[i].etc.status) != 0)
1484 {
1485 continue;
1486 }
1487
1488 // find the perfect match is possible
1489 if ((flag & NVT_FLAG_MAX_EDID_TIMING) == 0 &&
1490 width == pEdidTiming[i].HVisible &&
1491 height == frame_height(pEdidTiming[i]) &&
1492 rr == pEdidTiming[i].etc.rr &&
1493 ((rrx1k == 0) || (rrx1k == pEdidTiming[i].etc.rrx1k)) &&
1494 !!(flag & NVT_PVT_INTERLACED_MASK) == !!pEdidTiming[i].interlaced)
1495 {
1496 if (map0 >= pEdidInfo->total_timings || pEdidTiming[i].pclk == pclk)
1497 {
1498 // make sure we take the priority as "detailed>standard>established". (The array timing[] always have the detailed timings in the front and then the standard and established.)
1499 map0 = i;
1500 }
1501
1502 if ( (NVT_PREFERRED_TIMING_IS_CTA(pEdidTiming[i].etc.flag)) ||
1503 ((0 == (flag & NVT_FLAG_EDID_861_ST)) && NVT_PREFERRED_TIMING_IS_DTD1(pEdidTiming[i].etc.flag, pEdidTiming[i].etc.status)) ||
1504 (NVT_PREFERRED_TIMING_IS_DISPLAYID(pEdidTiming[i].etc.flag)) ||
1505 (NVT_IS_NATIVE_TIMING(pEdidTiming[i].etc.status)))
1506 {
1507 *pT = pEdidTiming[i];
1508 return NVT_STATUS_SUCCESS;
1509 }
1510
1511 if (NVT_GET_TIMING_STATUS_TYPE(pEdidTiming[i].etc.status) == NVT_TYPE_EDID_861ST)
1512 {
1513 if (ceaIndex == pEdidInfo->total_timings)
1514 {
1515 // Save the first entry found.
1516 ceaIndex = i;
1517 }
1518 else
1519 {
1520 if (((flag & NVT_FLAG_CEA_4X3_TIMING) && (pEdidTiming[i].etc.aspect == 0x40003)) ||
1521 ((flag & NVT_FLAG_CEA_16X9_TIMING) && (pEdidTiming[i].etc.aspect == 0x160009)))
1522 {
1523 // Use preferred aspect ratio if specified.
1524 ceaIndex = i;
1525 }
1526 }
1527 }
1528 } // if ((flag & NVT_FLAG_MAX_EDID_TIMING) == 0 &&
1529
1530 // bypass the custom timing to be select for the mismatch case
1531 if (NVT_GET_TIMING_STATUS_TYPE(pEdidTiming[i].etc.status) == NVT_TYPE_CUST ||
1532 NVT_IS_CUST_ENTRY(pEdidTiming[i].etc.status) != 0)
1533 {
1534 if (width != pEdidTiming[i].HVisible || height != frame_height(pEdidTiming[i]) || rr != pEdidTiming[i].etc.rr)
1535 {
1536 continue;
1537 }
1538 }
1539
1540 // find out the preferred timing just in case of cea_vfpdb is existed
1541 if (native_cta == pEdidInfo->total_timings && NVT_NATIVE_TIMING_IS_CTA(pEdidTiming[i].etc.flag))
1542 {
1543 native_cta = i;
1544 }
1545
1546 if (preferred_cta == pEdidInfo->total_timings && NVT_PREFERRED_TIMING_IS_CTA(pEdidTiming[i].etc.flag))
1547 {
1548 if (pEdidInfo->ext861.total_svr > 1)
1549 {
1550 if (kth != 0)
1551 {
1552 // svr == vic
1553 if (NVT_IS_CTA861(pEdidTiming[i].etc.status) && (NVT_GET_CEA_FORMAT(pEdidTiming[i].etc.status) == kth))
1554 {
1555 preferred_cta = i;
1556 }
1557 else if (NVT_GET_TIMING_STATUS_SEQ(pEdidTiming[i].etc.status) == kth)
1558 {
1559 preferred_cta = i;
1560 }
1561 }
1562 }
1563 else
1564 {
1565 preferred_cta = i;
1566 }
1567 }
1568
1569 // find out the preferred timing just in case
1570 // Caller we will force rr value as 1 to select the DisplayID prefer timing in pEdidTiming if it existed
1571 // however, we can't assign the correct refresh rate we want if we had two and above rr values which shared the same timing.
1572 if (rr != 1)
1573 {
1574 if (pEdidTiming[i].etc.rr == rr && NVT_PREFERRED_TIMING_IS_DISPLAYID(pEdidTiming[i].etc.flag))
1575 {
1576 preferred_displayid_dtd = i;
1577 }
1578 }
1579 else if (preferred_displayid_dtd == pEdidInfo->total_timings &&
1580 NVT_PREFERRED_TIMING_IS_DISPLAYID(pEdidTiming[i].etc.flag))
1581 {
1582 preferred_displayid_dtd = i;
1583 }
1584
1585 if (NVT_PREFERRED_TIMING_IS_DTD1(pEdidTiming[i].etc.flag, pEdidTiming[i].etc.status))
1586 {
1587 preferred_dtd1 = i;
1588 }
1589
1590 if (NVT_IS_DTD1(pEdidTiming[i].etc.status))
1591 {
1592 dtd1 = i;
1593 }
1594
1595 // find out the max mode just in case
1596 if (pEdidTiming[i].HVisible * pEdidTiming[i].VVisible > pEdidTiming[max].HVisible * pEdidTiming[max].VVisible)
1597 max = i;
1598
1599 // if the requested timing is not in the EDID, try to find out the EDID entry with the same progressive/interlaced setting
1600 if (map1 >= pEdidInfo->total_timings)
1601 {
1602 if (!!(flag & NVT_PVT_INTERLACED_MASK) == !!pEdidTiming[i].interlaced &&
1603 width <= pEdidTiming[i].HVisible &&
1604 height <= frame_height(pEdidTiming[i]))
1605 {
1606 map1 = i;
1607 }
1608 }
1609 else
1610 {
1611 if (!!(flag & NVT_PVT_INTERLACED_MASK) == !!pEdidTiming[i].interlaced &&
1612 width <= pEdidTiming[i].HVisible &&
1613 height <= frame_height(pEdidTiming[i]) &&
1614 abs_delta(pEdidTiming[i].HVisible, width) <= abs_delta(pEdidTiming[map1].HVisible, width) &&
1615 abs_delta(frame_height(pEdidTiming[i]), height) <= abs_delta(frame_height(pEdidTiming[map1]), height))
1616 {
1617 // if there're 2 timings with the same visible size, choose the one with closer refresh rate
1618 if (pEdidTiming[i].HVisible == pEdidTiming[map1].HVisible &&
1619 frame_height(pEdidTiming[i]) == frame_height(pEdidTiming[map1]))
1620 {
1621 if (abs_delta(pEdidTiming[i].etc.rr, rr) < abs_delta(pEdidTiming[map1].etc.rr, rr))
1622 {
1623 map1 = i;
1624 }
1625 }
1626 else
1627 {
1628 map1 = i;
1629 }
1630 }
1631 }
1632
1633 // if the requested timing is not in the EDID, try to find out the EDID entry without the progressive/interlaced setting
1634 if (map2 >= pEdidInfo->total_timings)
1635 {
1636 if (width <= pEdidTiming[i].HVisible &&
1637 height <= frame_height(pEdidTiming[i]))
1638 {
1639 map2 = i;
1640 }
1641 }
1642 else
1643 {
1644 if (width <= pEdidTiming[i].HVisible &&
1645 height <= frame_height(pEdidTiming[i]) &&
1646 abs_delta(pEdidTiming[i].HVisible, width) <= abs_delta(pEdidTiming[map2].HVisible, width) &&
1647 abs_delta(frame_height(pEdidTiming[i]), height) <= abs_delta(frame_height(pEdidTiming[map2]), height))
1648 {
1649 // if there're 2 timings with the same visible size, choose the one with closer refresh rate
1650 if (pEdidTiming[i].HVisible == pEdidTiming[map2].HVisible &&
1651 frame_height(pEdidTiming[i]) == frame_height(pEdidTiming[map2]))
1652 {
1653 if (abs_delta(pEdidTiming[i].etc.rr, rr) < abs_delta(pEdidTiming[map2].etc.rr, rr))
1654 {
1655 map2 = i;
1656 }
1657 }
1658 else
1659 {
1660 map2 = i;
1661 }
1662 }
1663 }
1664
1665 // find out the native timing
1666 if (NVT_IS_NATIVE_TIMING(pEdidTiming[i].etc.status) || NVT_IS_DTD1(pEdidTiming[i].etc.status))
1667 {
1668 if (map3 >= pEdidInfo->total_timings)
1669 {
1670 if (width <= pEdidTiming[i].HVisible &&
1671 height <= frame_height(pEdidTiming[i]))
1672 {
1673 map3 = i;
1674 }
1675 }
1676 else if(abs_delta(pEdidTiming[i].HVisible, width) <= abs_delta(pEdidTiming[map3].HVisible, width) &&
1677 abs_delta(frame_height(pEdidTiming[i]), height) <= abs_delta(frame_height(pEdidTiming[map3]), height) &&
1678 width <= pEdidTiming[i].HVisible &&
1679 height <= frame_height(pEdidTiming[i]))
1680 {
1681 map3 = i;
1682 }
1683 }
1684
1685 // find the edid timing with refresh rate matching
1686 if (map4 >= pEdidInfo->total_timings)
1687 {
1688 if (width <= pEdidTiming[i].HVisible &&
1689 height <= pEdidTiming[i].VVisible &&
1690 rr == pEdidTiming[i].etc.rr)
1691 {
1692 map4 = i;
1693 }
1694 }
1695 else
1696 {
1697 if (width <= pEdidTiming[i].HVisible &&
1698 height <= pEdidTiming[i].HVisible &&
1699 rr == pEdidTiming[i].etc.rr &&
1700 abs_delta(pEdidTiming[i].HVisible, width) <= abs_delta(pEdidTiming[map4].HVisible, width) &&
1701 abs_delta(pEdidTiming[i].VVisible, height) <= abs_delta(pEdidTiming[map4].VVisible, height))
1702 {
1703 map4 = i;
1704 }
1705 }
1706
1707 }//for (i = 0; i < pEdidInfo->total_timings; i++)
1708
1709 if ( (preferred_displayid_dtd == preferred_dtd1) && (preferred_dtd1 == dtd1) &&
1710 (dtd1 == map0) &&
1711 (map0 == map1) &&
1712 (map1 == map2) &&
1713 (map2 == map3) &&
1714 (map3 == map4) &&
1715 (map4 == pEdidInfo->total_timings) &&
1716 pEdidInfo->version >= NVT_EDID_VER_1_4 &&
1717 pEdidInfo->u.feature_ver_1_4_digital.continuous_frequency &&
1718 !(flag & NVT_PVT_INTERLACED_MASK))
1719 {
1720 // try to find CVT timing that fits
1721 NvU32 maxHeight, minHeight, tempHeight;
1722
1723 minHeight = ~0;
1724 maxHeight = tempHeight= 0;
1725
1726 // looping through long display descriptors
1727 for (i=0; i<NVT_EDID_MAX_LONG_DISPLAY_DESCRIPTOR; i++)
1728 {
1729 if (pEdidInfo->ldd[i].tag != NVT_EDID_DISPLAY_DESCRIPTOR_DRL || pEdidInfo->ldd[i].u.range_limit.timing_support != NVT_EDID_RANGE_SUPPORT_CVT)
1730 {
1731 continue;
1732 }
1733
1734 pCVT = &pEdidInfo->ldd[i].u.range_limit.u.cvt;
1735
1736 if (width <= pCVT->max_active_pixels_per_line || (pCVT->scaling_support & NVT_EDID_CVT_SCALING_HOR_SHRINK))
1737 {
1738 for (j=0; j<NVT_EDID_CVT_ASPECT_SUPPORT_MAX && !cvt; j++)
1739 {
1740 if ( !(pCVT->aspect_supported & (1<<j)))
1741 {
1742 continue;
1743 }
1744
1745 switch (1<<j)
1746 {
1747 case NVT_EDID_CVT_ASPECT_SUPPORT_4X3:
1748 tempHeight = axb_div_c(width, 3, 4);
1749 if (axb_div_c(width, 3, height) == 4) cvt = 1;
1750 break;
1751 case NVT_EDID_CVT_ASPECT_SUPPORT_16X9:
1752 tempHeight = axb_div_c(width, 9, 16);
1753 if (axb_div_c(width, 9, height) == 16) cvt = 1;
1754 break;
1755 case NVT_EDID_CVT_ASPECT_SUPPORT_16X10:
1756 tempHeight = axb_div_c(width, 10, 16);
1757 if (axb_div_c(width,10, height) == 16) cvt = 1;
1758 break;
1759 case NVT_EDID_CVT_ASPECT_SUPPORT_5X4:
1760 tempHeight = axb_div_c(width, 4, 5);
1761 if (axb_div_c(width, 4, height) == 5) cvt = 1;
1762 break;
1763 case NVT_EDID_CVT_ASPECT_SUPPORT_15X9:
1764 tempHeight = axb_div_c(width, 9, 15);
1765 if (axb_div_c(width, 9, height) == 15) cvt = 1;
1766 break;
1767 }
1768
1769 //keep track of max and min in case NVT_EDID_CVT_SCALING_VER_STRETCH/SHRINK are true
1770 if (minHeight > tempHeight)
1771 {
1772 minHeight = tempHeight;
1773 }
1774 if (maxHeight < tempHeight)
1775 {
1776 maxHeight = tempHeight;
1777 }
1778
1779 }//for (j=0; j<5; j++)
1780 }//if (width <= pCVT->max_active_pixels_per_line || (pCVT->scaling_support & NVT_EDID_CVT_SCALING_HOR_STRETCH))
1781
1782 if ( ((minHeight < height) && (pCVT->scaling_support & NVT_EDID_CVT_SCALING_VER_SHRINK)) ||
1783 ((maxHeight > height) && (pCVT->scaling_support & NVT_EDID_CVT_SCALING_VER_STRETCH)) )
1784 {
1785 cvt = 1;
1786 }
1787
1788 if (cvt)
1789 {
1790 break;
1791 }
1792 }//for (i=0; i<NVT_EDID_MAX_LONG_DISPLAY_DESCRIPTOR; i++)
1793
1794 if (cvt)
1795 {
1796 //calculate the CVT timing
1797 // pclk is in 10KHz, max_pclk_MHz is in MHz, pixel_clock_adjustment is in .25MHz - make sure timing pclk is inside the max pclk declared in the EDID
1798 if (pCVT->blanking_support & NVT_EDID_CVT_BLANKING_REDUCED && NvTiming_CalcCVT_RB(width, height, rr, NVT_PROGRESSIVE, &cvtTiming) == NVT_STATUS_SUCCESS)
1799 {
1800 if ( cvtTiming.pclk > (NvU32)((pEdidInfo->ldd[i].u.range_limit.max_pclk_MHz * 100) - (pCVT->pixel_clock_adjustment * 25)) )
1801 {
1802 cvt = 0;
1803 }
1804 }
1805 else if (pCVT->blanking_support & NVT_EDID_CVT_BLANKING_STANDARD && NvTiming_CalcCVT(width, height, rr, NVT_PROGRESSIVE, &cvtTiming) == NVT_STATUS_SUCCESS)
1806 {
1807 if ( cvtTiming.pclk > (NvU32)((pEdidInfo->ldd[i].u.range_limit.max_pclk_MHz * 100) - (pCVT->pixel_clock_adjustment * 25)) )
1808 {
1809 cvt = 0;
1810 }
1811 }
1812 else
1813 {
1814 cvt = 0;
1815 }
1816
1817 }
1818 }//(dtd1 == map0 == map1 == map2 == map3 == pEdidInfo->total_timings) && pEdidInfo->version >= NVT_EDID_VER_1_4 &&
1819 // pEdidInfo->feature_ver_1_4_digital.continuous_frequency && !(flag & NVT_PVT_INTERLACED_MASK))
1820
1821 // now return the mismatched EDID timing
1822 if (flag & NVT_FLAG_NV_PREFERRED_TIMING)
1823 {
1824 *pT = (preferred_displayid_dtd != pEdidInfo->total_timings) ? pEdidTiming[preferred_displayid_dtd] :
1825 (native_cta != pEdidInfo->total_timings) ? pEdidTiming[native_cta] :
1826 (preferred_cta != pEdidInfo->total_timings) ? pEdidTiming[preferred_cta] :
1827 (preferred_dtd1 != pEdidInfo->total_timings) ? pEdidTiming[preferred_dtd1] :
1828 pEdidTiming[dtd1];
1829 // what if DTD1 itself is filtered out, in such case dtd1 index points to an invalid timing[]?
1830 // (dtd1 != pEdidInfo->total_timings) ? pEdidTiming[dtd1] : pEdidTiming[0];
1831 }
1832 else if (flag & NVT_FLAG_DTD1_TIMING)
1833 {
1834 *pT = pEdidTiming[dtd1];
1835 }
1836 else if ((flag & NVT_FLAG_MAX_EDID_TIMING) && (0 == (flag & NVT_FLAG_EDID_861_ST)))
1837 {
1838 *pT = pEdidTiming[max];
1839 }
1840 else if ((flag & (NVT_FLAG_CEA_4X3_TIMING | NVT_FLAG_CEA_16X9_TIMING | NVT_FLAG_EDID_861_ST)) && ceaIndex < (pEdidInfo->total_timings))
1841 {
1842 *pT = pEdidTiming[ceaIndex];
1843 }
1844 else if ((flag & NVT_FLAG_NATIVE_TIMING) != 0 && map3 < pEdidInfo->total_timings)
1845 {
1846 // Allow closest refresh rate match when EDID has detailed timing for different RR on native resolution.
1847 if (map0 < pEdidInfo->total_timings &&
1848 pEdidTiming[map0].HVisible == pEdidTiming[map3].HVisible &&
1849 pEdidTiming[map0].VVisible == pEdidTiming[map3].VVisible)
1850 {
1851 *pT = pEdidTiming[map0];
1852 }
1853 else
1854 {
1855 *pT = pEdidTiming[map3];
1856 }
1857 }
1858 else if (map0 < pEdidInfo->total_timings)
1859 {
1860 // use the exact mapped timing if possible
1861 *pT = pEdidTiming[map0];
1862 }
1863 else if ((flag & NVT_FLAG_EDID_TIMING_RR_MATCH) && map4 < pEdidInfo->total_timings)
1864 {
1865 *pT = pEdidTiming[map4];
1866 }
1867 else if (map1 < pEdidInfo->total_timings)
1868 {
1869 // use the mapped timing if possible
1870 *pT = pEdidTiming[map1];
1871 }
1872 else if (map2 < pEdidInfo->total_timings)
1873 {
1874 // use the 2nd mapped timing if possible
1875 *pT = pEdidTiming[map2];
1876 }
1877 else if (dtd1 < pEdidInfo->total_timings && width <= pEdidTiming[dtd1].HVisible && height <= pEdidTiming[dtd1].VVisible)
1878 {
1879 // use the 1st detailed timing if possible
1880 *pT = pEdidTiming[dtd1];
1881 }
1882 else if (cvt)
1883 {
1884 // use the cvt timing
1885 *pT = cvtTiming;
1886 }
1887 else
1888 {
1889 // use the max timing for all other cases
1890 *pT = pEdidTiming[max];
1891 }
1892
1893 // set the mismatch status
1894 if (pT->HVisible != width || frame_height(*pT) != height)
1895 {
1896 NVT_SET_TIMING_STATUS_MISMATCH(pT->etc.status, NVT_STATUS_TIMING_MISMATCH_SIZE);
1897 }
1898 if (!NvTiming_IsRoundedRREqual(pT->etc.rr, pT->etc.rrx1k, (NvU16)rr))
1899 {
1900 NVT_SET_TIMING_STATUS_MISMATCH(pT->etc.status, NVT_STATUS_TIMING_MISMATCH_RR);
1901 }
1902 if (!!pT->interlaced != !!(flag & NVT_PVT_INTERLACED_MASK))
1903 {
1904 NVT_SET_TIMING_STATUS_MISMATCH(pT->etc.status, NVT_STATUS_TIMING_MISMATCH_FORMAT);
1905 }
1906
1907 return NVT_STATUS_SUCCESS;
1908 }
1909
CODE_SEGMENT(PAGE_DD_CODE)1910 CODE_SEGMENT(PAGE_DD_CODE)
1911 NVT_STATUS NvTiming_GetEdidTimingEx(NvU32 width, NvU32 height, NvU32 rr, NvU32 flag, NVT_EDID_INFO *pEdidInfo, NVT_TIMING *pT, NvU32 rrx1k)
1912 {
1913 return NvTiming_GetEdidTimingExWithPclk(width, height, rr, flag, pEdidInfo, pT, rrx1k, 0);
1914 }
1915
1916 // get the edid timing
CODE_SEGMENT(PAGE_DD_CODE)1917 CODE_SEGMENT(PAGE_DD_CODE)
1918 NVT_STATUS NvTiming_GetEdidTiming(NvU32 width, NvU32 height, NvU32 rr, NvU32 flag, NVT_EDID_INFO *pEdidInfo, NVT_TIMING *pT)
1919 {
1920 return NvTiming_GetEdidTimingEx(width, height, rr, flag, pEdidInfo, pT, 0);
1921 }
CODE_SEGMENT(PAGE_DD_CODE)1922 CODE_SEGMENT(PAGE_DD_CODE)
1923 NVT_STATUS NvTiming_GetHDMIStereoExtTimingFromEDID(NvU32 width, NvU32 height, NvU32 rr, NvU8 StereoStructureType, NvU8 SideBySideHalfDetail, NvU32 flag, NVT_EDID_INFO *pEdidInfo, NVT_EXT_TIMING *pT)
1924 {
1925 NVT_STATUS status = NVT_STATUS_ERR;
1926 NvU8 Vic;
1927 NvU32 i;
1928 NVT_TIMING Timing;
1929
1930 NVMISC_MEMSET(pT, 0, sizeof(NVT_EXT_TIMING));
1931
1932 // adjust the flags --
1933 // need EDID timing with RR match,
1934 // not max timing,
1935 flag = flag | NVT_FLAG_EDID_TIMING | NVT_FLAG_EDID_TIMING_RR_MATCH | NVT_FLAG_EDID_861_ST;
1936 flag = flag & ~(NVT_FLAG_MAX_EDID_TIMING);
1937
1938 status = NvTiming_GetEdidTiming(width, height, rr, flag, pEdidInfo, &Timing);
1939 if (NVT_STATUS_SUCCESS == status)
1940 {
1941 status = NVT_STATUS_ERR;
1942
1943 // is this an exact match?
1944 if (0 == NVT_GET_TIMING_STATUS_MATCH(Timing.etc.status))
1945 {
1946 if (NVT_TYPE_EDID_861ST == NVT_GET_TIMING_STATUS_TYPE(Timing.etc.status))
1947 {
1948 // lookup the vic for this timing in the support map.
1949 Vic = (NvU8) NVT_GET_CEA_FORMAT(Timing.etc.status);
1950 for (i = 0; i < pEdidInfo->Hdmi3Dsupport.total; ++i)
1951 {
1952 if (Vic == pEdidInfo->Hdmi3Dsupport.map[i].Vic)
1953 {
1954 break;
1955 }
1956 }
1957 if (i < pEdidInfo->Hdmi3Dsupport.total)
1958 {
1959 // does this vic support the requested structure type?
1960 if (0 != (NVT_HDMI_3D_SUPPORTED_STRUCT_MASK(StereoStructureType) & pEdidInfo->Hdmi3Dsupport.map[i].StereoStructureMask))
1961 {
1962 // if this is side-by-side(half) the detail needs to match also.
1963 if ((NVT_HDMI_VS_BYTE5_HDMI_3DS_SIDEBYSIDEHALF != StereoStructureType) || (SideBySideHalfDetail == pEdidInfo->Hdmi3Dsupport.map[i].SideBySideHalfDetail))
1964 {
1965 // convert the 2D timing to 3D.
1966 NvTiming_GetHDMIStereoTimingFrom2DTiming(&Timing, StereoStructureType, SideBySideHalfDetail, pT);
1967 status = NVT_STATUS_SUCCESS;
1968 }
1969 }
1970 }
1971 }
1972 }
1973 }
1974 return status;
1975 }
1976
1977 // EDID based AspectRatio Timing
CODE_SEGMENT(PAGE_DD_CODE)1978 CODE_SEGMENT(PAGE_DD_CODE)
1979 NVT_STATUS NvTiming_GetEDIDBasedASPRTiming( NvU16 width, NvU16 height, NvU16 rr, NVT_EDID_INFO *pEI, NVT_TIMING *pT)
1980 {
1981 NvU32 i, dwStatus;
1982 NvU32 dwNativeIndex;
1983 NvU32 flag;
1984 NvU32 ret;
1985
1986 // sanity check
1987 if( pEI == NULL || pEI->total_timings == 0 || pT == NULL )
1988 {
1989 return NVT_STATUS_ERR;
1990 }
1991 if( width == 0 || height == 0 )
1992 {
1993 return NVT_STATUS_ERR;
1994 }
1995
1996 // get an EDID timing. Return err if it fails as we don't have any timing to tweak.
1997 flag = 0;
1998 ret = NvTiming_GetEdidTiming(width, height, rr, flag, pEI, pT);
1999 if( NVT_STATUS_SUCCESS != ret )
2000 {
2001 return NVT_STATUS_ERR;
2002 }
2003 // in case we have an exact match from EDID (in terms of Size), we return Success.
2004 else if ((NVT_GET_TIMING_STATUS_MATCH(pT->etc.status) & NVT_STATUS_TIMING_MISMATCH_SIZE) == 0)
2005 {
2006 return NVT_STATUS_SUCCESS;
2007 }
2008
2009 // find the Native timing
2010 for (i = 0, dwNativeIndex = pEI->total_timings + 1; i < pEI->total_timings; i++)
2011 {
2012 dwStatus = pEI->timing[i].etc.status;
2013
2014 if ((NVT_IS_NATIVE_TIMING(dwStatus)) || NVT_IS_DTD1(dwStatus))
2015 {
2016 dwNativeIndex = i;
2017 break;
2018 }
2019 }
2020
2021 // we don't want to apply LogicScaling(Letterboxing) to Wide Mode on Wide Panel (or non-Wide Mode on non-Wide Panel)
2022 if( nvt_is_wideaspect(width, height) == nvt_is_wideaspect(pEI->timing[dwNativeIndex].HVisible, pEI->timing[dwNativeIndex].VVisible) )
2023 {
2024 return NVT_STATUS_ERR;
2025 }
2026
2027 // Letterbox mode enabled by regkey LogicScalingMode
2028 // When we try to set modes not supported in EDID (eg. DFP over DSub) the display may not fit the screen.
2029 // If Logic Scaling is enabled (ie why we are here), we need to tweak the timing (for CRT) provided:
2030 // 1) the aspect ratio of native mode and requested mode differ
2031 // eg. Native AR = 5:4, 1280x1024
2032 // Requested AR = 16:10, 1280x800
2033 // 2) Both Width and Height do not mismatch together; If they do we shall go in for DMT/GTF timing
2034 // by failing this call.
2035 if( pT->interlaced == 0 &&
2036 dwNativeIndex < pEI->total_timings &&
2037 (pEI->timing[dwNativeIndex].HVisible*height != pEI->timing[dwNativeIndex].VVisible*width) &&
2038 (width == pT->HVisible || height == pT->VVisible))
2039 {
2040 pT->HFrontPorch += (pT->HVisible - width) / 2;
2041 pT->VFrontPorch += (pT->VVisible - height) / 2;
2042 pT->HVisible = width;
2043 pT->VVisible = height;
2044 if(rr != pT->etc.rr)
2045 {
2046 pT->etc.rrx1k = rr * 1000;
2047 pT->pclk = RRx1kToPclk (pT);
2048 }
2049
2050 pT->etc.status = NVT_STATUS_ASPR;
2051 return NVT_STATUS_SUCCESS;
2052 }
2053
2054 return NVT_STATUS_ERR;
2055 }
2056
2057 /**
2058 *
2059 * @brief check EDID raw data is valid or not, and it will return the err flags if it existed
2060 * @param pEdid : this is a pointer to EDID data
2061 * @param length : read length of EDID
2062 * @param bIsTrongValidation : true - added more check
2063 * false- only header and checksum and size check
2064 *
2065 */
CODE_SEGMENT(PAGE_DD_CODE)2066 CODE_SEGMENT(PAGE_DD_CODE)
2067 NvU32 NvTiming_EDIDValidationMask(NvU8 *pEdid, NvU32 length, NvBool bIsStrongValidation)
2068 {
2069 NvU32 i, j, version, checkSum;
2070 EDIDV1STRUC *p = (EDIDV1STRUC *)pEdid;
2071 EDID_LONG_DISPLAY_DESCRIPTOR *pLdd;
2072 NvU8 *pExt;
2073 DETAILEDTIMINGDESCRIPTOR *pDTD;
2074 NvU32 ret = 0;
2075
2076 // check the EDID base size to avoid accessing beyond the EDID buffer, do not proceed with
2077 // further validation.
2078 if (length < sizeof(EDIDV1STRUC))
2079 {
2080 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_SIZE);
2081 return ret;
2082 }
2083
2084 // check the EDID version and signature
2085 if (getEdidVersion(pEdid, &version) != NVT_STATUS_SUCCESS)
2086 {
2087 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_VERSION);
2088 return ret;
2089 }
2090
2091 // check block 0 checksum value
2092 if (!isChecksumValid(pEdid))
2093 {
2094 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_CHECKSUM);
2095 return ret;
2096 }
2097
2098 // Strong validation to follow
2099 if (bIsStrongValidation == NV_TRUE)
2100 {
2101 // range limit check
2102 for (i = 0; i < NVT_EDID_MAX_LONG_DISPLAY_DESCRIPTOR; i++)
2103 {
2104 pLdd = (EDID_LONG_DISPLAY_DESCRIPTOR *)&p->DetailedTimingDesc[i];
2105 if (pLdd->tag == NVT_EDID_DISPLAY_DESCRIPTOR_DRL && (version == 0x103 || (version == 0x104 && (p->bFeatureSupport & 1))))
2106 {
2107 EDID_MONITOR_RANGE_LIMIT *pRangeLimit = (EDID_MONITOR_RANGE_LIMIT *)pLdd->data;
2108 NvU8 max_v_rate_offset, min_v_rate_offset, max_h_rate_offset, min_h_rate_offset;
2109
2110 // add 255Hz offsets as needed before doing the check, use descriptor->rsvd2
2111 nvt_assert(!(pLdd->rsvd2 & 0xF0));
2112
2113 max_v_rate_offset = pLdd->rsvd2 & NVT_PVT_EDID_RANGE_OFFSET_VER_MAX ? NVT_PVT_EDID_RANGE_OFFSET_AMOUNT : 0;
2114 min_v_rate_offset = pLdd->rsvd2 & NVT_PVT_EDID_RANGE_OFFSET_VER_MIN ? NVT_PVT_EDID_RANGE_OFFSET_AMOUNT : 0;
2115 max_h_rate_offset = pLdd->rsvd2 & NVT_PVT_EDID_RANGE_OFFSET_HOR_MAX ? NVT_PVT_EDID_RANGE_OFFSET_AMOUNT : 0;
2116 min_h_rate_offset = pLdd->rsvd2 & NVT_PVT_EDID_RANGE_OFFSET_HOR_MIN ? NVT_PVT_EDID_RANGE_OFFSET_AMOUNT : 0;
2117
2118 if ((pRangeLimit->minVRate + min_v_rate_offset) > (pRangeLimit->maxVRate + max_v_rate_offset) ||
2119 (pRangeLimit->minHRate + min_h_rate_offset) > (pRangeLimit->maxHRate + max_h_rate_offset) ||
2120 pRangeLimit->maxVRate == 0 ||
2121 pRangeLimit->maxHRate == 0)
2122 {
2123 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_RANGE_LIMIT);
2124 }
2125 break;
2126 }
2127 }
2128
2129 // extension and size check
2130 if ((NvU32)(p->bExtensionFlag + 1) * sizeof(EDIDV1STRUC) > length)
2131 {
2132 // Do not proceed with further validation if the size is invalid.
2133 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_SIZE);
2134 return ret;
2135 }
2136
2137 // validate Detailed Timing Descriptors, 4 blocks
2138 for (i = 0; i < 4; i++)
2139 {
2140 if (*((NvU16 *)&p->DetailedTimingDesc[i]) != 0)
2141 {
2142 // This block is not a Display Descriptor.
2143 // It must be a valid timing definition
2144 // validate the block by passing NULL as the NVTIMING parameter to parseEdidDetailedTimingDescriptor
2145 if (parseEdidDetailedTimingDescriptor((NvU8 *)&p->DetailedTimingDesc[i], NULL) != NVT_STATUS_SUCCESS)
2146 {
2147 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_DTD);
2148 }
2149 }
2150 else
2151 {
2152 // This block is a display descriptor, validate
2153 if (((EDID_LONG_DISPLAY_DESCRIPTOR *)&p->DetailedTimingDesc[i])->rsvd != 0)
2154 {
2155 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_DTD);
2156 }
2157 }
2158 }
2159
2160 // validate extension blocks
2161 for (j = 1; j <= p->bExtensionFlag; j++)
2162 {
2163 pExt = pEdid + sizeof(EDIDV1STRUC) * j;
2164
2165 // check for 861 extension
2166 switch (*pExt)
2167 {
2168 case NVT_EDID_EXTENSION_CTA:
2169 // first sanity check on the extension block
2170 if (get861ExtInfo(pExt, sizeof(EIA861EXTENSION), NULL) != NVT_STATUS_SUCCESS)
2171 {
2172 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT);
2173 }
2174
2175 // check sum on CEA extension block
2176 for (i = 0, checkSum = 0; i < sizeof(EIA861EXTENSION); i ++)
2177 {
2178 checkSum += pExt[i];
2179 }
2180
2181 if ((checkSum & 0xFF) != 0)
2182 {
2183 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_CHECKSUM);
2184 }
2185
2186 // 0 indicates no DTD in this block
2187 if (((EIA861EXTENSION*)pExt)->offset == 0)
2188 {
2189 continue;
2190 }
2191
2192 // validate DTD blocks
2193 pDTD = (DETAILEDTIMINGDESCRIPTOR *)&pExt[((EIA861EXTENSION *)pExt)->offset];
2194 while ((pDTD->wDTPixelClock != 0) &&
2195 (((NvU8 *)pDTD - pExt + sizeof(DETAILEDTIMINGDESCRIPTOR)) < ((NvU8)sizeof(EIA861EXTENSION))))
2196 {
2197 if (parseEdidDetailedTimingDescriptor((NvU8 *)pDTD, NULL) != NVT_STATUS_SUCCESS)
2198 {
2199 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DTD);
2200 }
2201 pDTD++;
2202 }
2203 break;
2204 case NVT_EDID_EXTENSION_VTB:
2205 // perform a checksum on the VTB block
2206 for (i = 0, checkSum = 0; i < sizeof(VTBEXTENSION); i++)
2207 {
2208 checkSum += pExt[i];
2209 }
2210 if ((checkSum & 0xFF) != 0)
2211 {
2212 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_CHECKSUM);
2213 }
2214 break;
2215 case NVT_EDID_EXTENSION_DISPLAYID:
2216 // perform a checksum on the VTB block
2217 for (i = 0, checkSum = 0; i < sizeof(EIA861EXTENSION); i++)
2218 {
2219 checkSum += pExt[i];
2220 }
2221 if ((checkSum & 0xFF) != 0)
2222 {
2223 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_CHECKSUM);
2224 }
2225 break;
2226 default:
2227 break;
2228 }
2229 }
2230 }
2231
2232 return ret;
2233 }
2234
2235 /**
2236 *
2237 * @brief sanity check EDID binary frequently used data block is valid or not,
2238 * and it will return error checkpoint flag if it existed
2239 * @param pEdid : this is a pointer to EDID raw data
2240 * @param length : read length of EDID
2241 *
2242 */
CODE_SEGMENT(PAGE_DD_CODE)2243 CODE_SEGMENT(PAGE_DD_CODE)
2244 NvU32 NvTiming_EDIDStrongValidationMask(NvU8 *pEdid, NvU32 length)
2245 {
2246 NvU32 i, j, version, extnCount;
2247 EDIDV1STRUC *p = (EDIDV1STRUC *)pEdid;
2248 EDID_LONG_DISPLAY_DESCRIPTOR *pLdd;
2249 NvU8 *pExt;
2250 DETAILEDTIMINGDESCRIPTOR *pDTD;
2251 // For CTA861
2252 NvU8 ctaDTD_Offset;
2253 NvU8 *pData_collection;
2254 NvU32 ctaBlockTag, ctaPayload, vic;
2255 // For DisplayID
2256 DIDEXTENSION *pDisplayid;
2257 NvU8 did_section_length = 0x79;
2258 NvU8 did2ExtCount = 0;
2259 DISPLAYID_2_0_DATA_BLOCK_HEADER *pDID2Header;
2260 DISPLAYID_DATA_BLOCK_HEADER *pHeader;
2261 NvU8 block_length = 0;
2262 NvBool bAllZero = NV_TRUE;
2263 NvU32 ret = 0;
2264
2265 // check the EDID base size to avoid accessing beyond the EDID buffer
2266 if (length < sizeof(EDIDV1STRUC) || (length > sizeof(EDIDV1STRUC) && (length % sizeof(EDIDV1STRUC) != 0)))
2267 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_SIZE);
2268
2269 // check the EDID version and signature
2270 if (getEdidVersion(pEdid, &version) != NVT_STATUS_SUCCESS)
2271 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_HEADER);
2272
2273 // check block 0 checksum value
2274 if (!isChecksumValid(pEdid))
2275 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_CHECKSUM);
2276
2277 if (p->bVersionNumber != 0x01 || p->bRevisionNumber > 0x04)
2278 {
2279 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_VERSION);
2280 }
2281
2282 // 18bytes in DTD or Display Descriptor check
2283 for (i = 0; i < NVT_EDID_MAX_LONG_DISPLAY_DESCRIPTOR; i++)
2284 {
2285 if (*((NvU16 *)&p->DetailedTimingDesc[i]) != 0)
2286 {
2287 // This block is not a Display Descriptor.
2288 // It must be a valid timing definition
2289 // validate the block by passing NULL as the NVTIMING parameter to parseEdidDetailedTimingDescriptor
2290 if (parseEdidDetailedTimingDescriptor((NvU8 *)&p->DetailedTimingDesc[i], NULL) != NVT_STATUS_SUCCESS)
2291 {
2292 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_DTD);
2293 }
2294 else
2295 {
2296 // check the max image size in monitor and its DTD defines value
2297 if (p->bMaxHorizImageSize != 0 && p->bMaxVertImageSize != 0)
2298 {
2299 DETAILEDTIMINGDESCRIPTOR *pDTD = (DETAILEDTIMINGDESCRIPTOR *)&p->DetailedTimingDesc[i];
2300 NvU16 hDTDImageSize = (pDTD->bDTHorizVertImage & 0xF0) << 4 | pDTD->bDTHorizontalImage;
2301 NvU16 vDTDImageSize = (pDTD->bDTHorizVertImage & 0x0F) << 8 | pDTD->bDTVerticalImage;
2302
2303 if ((hDTDImageSize/10) > p->bMaxHorizImageSize || (vDTDImageSize/10) > p->bMaxVertImageSize)
2304 {
2305 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_DTD);
2306 }
2307 }
2308 }
2309 }
2310 else
2311 {
2312 pLdd = (EDID_LONG_DISPLAY_DESCRIPTOR *)&p->DetailedTimingDesc[i];
2313
2314 // This block is a display descriptor, validate
2315 if (((EDID_LONG_DISPLAY_DESCRIPTOR *)&p->DetailedTimingDesc[i])->rsvd != 0 || // (00 00 00)h indicates Display Descriptor
2316 (pLdd->tag >= 0x11 && pLdd->tag <= 0xF6)) // Reserved : Do Not Use
2317 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_DESCRIPTOR);
2318
2319 if (pLdd->tag == NVT_EDID_DISPLAY_DESCRIPTOR_DRL && (version == 0x103 || (version == 0x104 && (p->bFeatureSupport & 1))))
2320 {
2321 EDID_MONITOR_RANGE_LIMIT *pRangeLimit = (EDID_MONITOR_RANGE_LIMIT *)pLdd->data;
2322 NvU8 max_v_rate_offset, min_v_rate_offset, max_h_rate_offset, min_h_rate_offset;
2323
2324 // add 255Hz offsets as needed before doing the check, use descriptor->rsvd2
2325 nvt_assert(!(pLdd->rsvd2 & 0xF0));
2326
2327 max_v_rate_offset = pLdd->rsvd2 & NVT_PVT_EDID_RANGE_OFFSET_VER_MAX ? NVT_PVT_EDID_RANGE_OFFSET_AMOUNT : 0;
2328 min_v_rate_offset = pLdd->rsvd2 & NVT_PVT_EDID_RANGE_OFFSET_VER_MIN ? NVT_PVT_EDID_RANGE_OFFSET_AMOUNT : 0;
2329 max_h_rate_offset = pLdd->rsvd2 & NVT_PVT_EDID_RANGE_OFFSET_HOR_MAX ? NVT_PVT_EDID_RANGE_OFFSET_AMOUNT : 0;
2330 min_h_rate_offset = pLdd->rsvd2 & NVT_PVT_EDID_RANGE_OFFSET_HOR_MIN ? NVT_PVT_EDID_RANGE_OFFSET_AMOUNT : 0;
2331
2332 if ((pRangeLimit->minVRate + min_v_rate_offset) > (pRangeLimit->maxVRate + max_v_rate_offset) ||
2333 (pRangeLimit->minHRate + min_h_rate_offset) > (pRangeLimit->maxHRate + max_h_rate_offset) ||
2334 pRangeLimit->maxVRate == 0 ||
2335 pRangeLimit->maxHRate == 0)
2336 {
2337 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_RANGE_LIMIT);
2338 }
2339 }
2340 }
2341 }
2342
2343 // extension and size check
2344 if ((NvU32)(p->bExtensionFlag + 1) * sizeof(EDIDV1STRUC) > length)
2345 {
2346 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXTENSION_COUNT);
2347 }
2348
2349 // we shall not trust any extension blocks with wrong input EDID size
2350 if (NVT_IS_EDID_VALIDATION_FLAGS(ret, NVT_EDID_VALIDATION_ERR_SIZE) ||
2351 NVT_IS_EDID_VALIDATION_FLAGS(ret, NVT_EDID_VALIDATION_ERR_EXTENSION_COUNT))
2352 return ret;
2353
2354 // validate extension blocks
2355 for (j = 1; j <= p->bExtensionFlag; j++)
2356 {
2357 pExt = pEdid + sizeof(EDIDV1STRUC) * j;
2358
2359 // check for 861 extension
2360 switch (*pExt)
2361 {
2362 case NVT_EDID_EXTENSION_CTA:
2363 ctaDTD_Offset = ((EIA861EXTENSION *)pExt)->offset;
2364 // first sanity check on the extension block
2365 if (get861ExtInfo(pExt, sizeof(EIA861EXTENSION), NULL) != NVT_STATUS_SUCCESS ||
2366 ((EIA861EXTENSION *)pExt)->revision < NVT_CEA861_REV_B)
2367 {
2368 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_CTA_BASIC);
2369 }
2370
2371 // 0 indicated there is no DTD and data collection in this block
2372 if (ctaDTD_Offset == 0)
2373 {
2374 if(!isChecksumValid(pExt))
2375 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_CTA_CHECKSUM);
2376 continue;
2377 }
2378
2379 // validate SVD block
2380 ctaBlockTag = NVT_CEA861_GET_SHORT_DESCRIPTOR_TAG(((EIA861EXTENSION *)pExt)->data[0]);
2381 pData_collection = ((EIA861EXTENSION *)pExt)->data;
2382
2383 while ((ctaDTD_Offset - 4) > 0 && pData_collection != &pExt[ctaDTD_Offset] &&
2384 ctaBlockTag > NVT_CEA861_TAG_RSVD && ctaBlockTag <= NVT_CEA861_TAG_EXTENDED_FLAG)
2385 {
2386 ctaBlockTag = NVT_CEA861_GET_SHORT_DESCRIPTOR_TAG(*pData_collection);
2387 ctaPayload = NVT_CEA861_GET_SHORT_DESCRIPTOR_SIZE(*pData_collection);
2388
2389 if (parseCta861DataBlockInfo(pData_collection, (NvU32)ctaDTD_Offset - 4, NULL) == NVT_STATUS_SUCCESS)
2390 {
2391 pData_collection++; // go to the next byte. skip Tag+Length byte
2392
2393 if (ctaBlockTag == NVT_CEA861_TAG_VIDEO)
2394 {
2395 for (i=0; i < ctaPayload; i++)
2396 {
2397 vic = NVT_GET_CTA_8BIT_VIC(*pData_collection);
2398 if (vic == 0 || vic > 255 || (vic >= 128 && vic <=192))
2399 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_CTA_SVD);
2400 pData_collection++;
2401 }
2402 }
2403 else if (ctaBlockTag == NVT_CEA861_TAG_EXTENDED_FLAG)
2404 {
2405 if (*pData_collection == NVT_CTA861_EXT_TAG_HF_EEODB)
2406 {
2407 if ((p->bVersionNumber != 0x01) || (p->bRevisionNumber != 0x03))
2408 {
2409 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_CTA_INVALID_DATA_BLOCK);
2410 pData_collection += ctaPayload;
2411 }
2412 else
2413 {
2414 ret &= ~NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXTENSION_COUNT);
2415 extnCount = *(++pData_collection);
2416 // check the EDID extension count value again because EDID extension block count
2417 // value in EEODB override it and source shall ignore extension flag > 1 value
2418 if ((extnCount + 1) != (length / (sizeof(EDIDV1STRUC))))
2419 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXTENSION_COUNT);
2420 pData_collection++;
2421 }
2422 }
2423 else
2424 pData_collection += ctaPayload;
2425 }
2426 else if (ctaBlockTag == NVT_CEA861_TAG_RSVD)
2427 {
2428 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_CTA_TAG);
2429 pData_collection += ctaPayload;
2430 }
2431 else
2432 pData_collection += ctaPayload;
2433 }
2434 else
2435 {
2436 pData_collection++; // go to the next byte. skip Tag+Length byte
2437
2438 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_CTA_INVALID_DATA_BLOCK);
2439 pData_collection += ctaPayload;
2440 }
2441 }
2442
2443 // validate DTD blocks
2444 pDTD = (DETAILEDTIMINGDESCRIPTOR *)&pExt[((EIA861EXTENSION *)pExt)->offset];
2445 while ((pDTD->wDTPixelClock != 0) &&
2446 (((NvU8 *)pDTD - pExt + sizeof(DETAILEDTIMINGDESCRIPTOR)) < ((NvU8)sizeof(EIA861EXTENSION))))
2447 {
2448 if (parseEdidDetailedTimingDescriptor((NvU8 *)pDTD, NULL) != NVT_STATUS_SUCCESS)
2449 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DTD);
2450 else
2451 {
2452 // check the max image size and
2453 if (p->bMaxHorizImageSize != 0 && p->bMaxVertImageSize != 0)
2454 {
2455 NvU16 hDTDImageSize = (pDTD->bDTHorizVertImage & 0xF0) << 4 | pDTD->bDTHorizontalImage;
2456 NvU16 vDTDImageSize = (pDTD->bDTHorizVertImage & 0x0F) << 8 | pDTD->bDTVerticalImage;
2457
2458 if ((hDTDImageSize/10) > (p->bMaxHorizImageSize) || (vDTDImageSize/10) > p->bMaxVertImageSize)
2459 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_CTA_DTD);
2460 }
2461 }
2462 pDTD++;
2463 }
2464
2465 if(!isChecksumValid(pExt))
2466 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_CTA_CHECKSUM);
2467 break;
2468 case NVT_EDID_EXTENSION_DISPLAYID:
2469 pDisplayid = ((DIDEXTENSION *)pExt);
2470 if (pDisplayid->ext_count != 0)
2471 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DID_EXTCOUNT);
2472
2473 if (pDisplayid->length != 0x79)
2474 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DID_SEC_SIZE);
2475
2476 if (!isChecksumValid(pExt))
2477 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DID_CHECKSUM);
2478
2479 // check the DID2 data blocks
2480 if ((pDisplayid->struct_version & 0xF0) >> 4 == 2)
2481 {
2482 if ((pDisplayid->struct_version & 0xFF) == 0x21)
2483 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DID_VERSION);
2484
2485 did2ExtCount++;
2486
2487 if (pDisplayid->use_case == 0 && did2ExtCount == 1)
2488 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DID2_USE_CASE);
2489
2490 // check the DisplayId2 valid timing
2491 pDID2Header = (DISPLAYID_2_0_DATA_BLOCK_HEADER*)pDisplayid->data;
2492 pData_collection = pDisplayid->data;
2493
2494 // Sanity check every data blocks
2495 while (((pDID2Header->type >= DISPLAYID_2_0_BLOCK_TYPE_PRODUCT_IDENTITY &&
2496 pDID2Header->type <= DISPLAYID_2_0_BLOCK_TYPE_BRIGHTNESS_LUMINANCE_RANGE) ||
2497 pDID2Header->type == DISPLAYID_2_0_BLOCK_TYPE_VENDOR_SPEC ||
2498 pDID2Header->type == DISPLAYID_2_0_BLOCK_TYPE_CTA_DATA) && pDID2Header->data_bytes != 0 &&
2499 (pData_collection - pExt < (int)sizeof(DIDEXTENSION)))
2500 {
2501 if (parseDisplayId20EDIDExtDataBlocks(pData_collection, did_section_length, &block_length, NULL) == NVT_STATUS_ERR)
2502 {
2503 if (pDID2Header->type == DISPLAYID_2_0_BLOCK_TYPE_TIMING_7)
2504 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DID2_TYPE7);
2505
2506 if (pDID2Header->type == DISPLAYID_2_0_BLOCK_TYPE_RANGE_LIMITS)
2507 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_RANGE_LIMIT);
2508
2509 if (pDID2Header->type == DISPLAYID_2_0_BLOCK_TYPE_ADAPTIVE_SYNC)
2510 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DID2_ADAPTIVE_SYNC);
2511 // add more data blocks tag here to evaluate
2512 }
2513 pData_collection += block_length;
2514 pDID2Header = (DISPLAYID_2_0_DATA_BLOCK_HEADER*)pData_collection;
2515 }
2516
2517 // compare the remain 0 value are correct or not before meet checksum byte
2518 for (i = 0; i < (NvU32)(&pDisplayid->data[NVT_DID_MAX_EXT_PAYLOAD-1] - pData_collection); i++)
2519 {
2520 if (pData_collection[i] != 0)
2521 {
2522 bAllZero = NV_FALSE;
2523 break;
2524 }
2525 }
2526
2527 // if the first tag failed, ignore all the tags afterward then
2528 if (!bAllZero &&
2529 (pDID2Header->type < DISPLAYID_2_0_BLOCK_TYPE_PRODUCT_IDENTITY ||
2530 (pDID2Header->type > DISPLAYID_2_0_BLOCK_TYPE_BRIGHTNESS_LUMINANCE_RANGE &&
2531 pDID2Header->type != DISPLAYID_2_0_BLOCK_TYPE_VENDOR_SPEC &&
2532 pDID2Header->type != DISPLAYID_2_0_BLOCK_TYPE_CTA_DATA)) &&
2533 (pData_collection - pExt < (int)sizeof(DIDEXTENSION)))
2534 {
2535 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DID2_TAG);
2536 continue;
2537 }
2538 }
2539 else if ((pDisplayid->struct_version & 0xFF) == 0x12 || (pDisplayid->struct_version & 0xFF) == 0x13)
2540 {
2541 if ((pDisplayid->struct_version & 0xFF) == 0x13)
2542 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DID_VERSION);
2543
2544 pHeader = (DISPLAYID_DATA_BLOCK_HEADER*)pDisplayid->data;
2545 pData_collection = pDisplayid->data;
2546
2547 // Sanity check every data blocks
2548 while ((pHeader->type <= NVT_DISPLAYID_BLOCK_TYPE_TILEDDISPLAY ||
2549 pHeader->type == NVT_DISPLAYID_BLOCK_TYPE_CTA_DATA ||
2550 pHeader->type == NVT_DISPLAYID_BLOCK_TYPE_VENDOR_SPEC) && pHeader->data_bytes != 0 &&
2551 (pData_collection - pExt < (int)sizeof(DIDEXTENSION)))
2552 {
2553 if (parseDisplayIdBlock(pData_collection, did_section_length, &block_length, NULL) == NVT_STATUS_ERR)
2554 {
2555 if (pHeader->type == NVT_DISPLAYID_BLOCK_TYPE_TIMING_1)
2556 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DID13_TYPE1);
2557
2558 if (pHeader->type == NVT_DISPLAYID_BLOCK_TYPE_RANGE_LIMITS)
2559 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_RANGE_LIMIT);
2560
2561 // add more data blocks tag here to evaluate
2562 }
2563 pData_collection += block_length;
2564 pHeader = (DISPLAYID_DATA_BLOCK_HEADER*)pData_collection;
2565 }
2566
2567 // compare the remain 0 value are correct or not before meet checksum byte
2568 for (i = 0; i < (NvU32)(&pDisplayid->data[NVT_DID_MAX_EXT_PAYLOAD-1] - pData_collection); i++)
2569 {
2570 if (pData_collection[i] != 0)
2571 {
2572 bAllZero = NV_FALSE;
2573 break;
2574 }
2575 }
2576
2577 // if the first tag failed, ignore all the tags afterward then
2578 if (!bAllZero &&
2579 pHeader->type > NVT_DISPLAYID_BLOCK_TYPE_TILEDDISPLAY &&
2580 pHeader->type != NVT_DISPLAYID_BLOCK_TYPE_CTA_DATA &&
2581 pHeader->type != NVT_DISPLAYID_BLOCK_TYPE_VENDOR_SPEC &&
2582 (pData_collection - pExt < (int)sizeof(DIDEXTENSION)))
2583 {
2584 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DID13_TAG);
2585 continue;
2586 }
2587 }
2588 else
2589 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DID_VERSION);
2590 break;
2591 default:
2592 // the useful extension only CTA (0x02) and DisplayID (0x70)
2593 if ( *pExt != NVT_EDID_EXTENSION_VTB && *pExt != NVT_EDID_EXTENSION_DI &&
2594 *pExt != NVT_EDID_EXTENSION_LS && *pExt != NVT_EDID_EXTENSION_DPVL &&
2595 *pExt != NVT_EDID_EXTENSION_BM && *pExt != NVT_EDID_EXTENSION_OEM )
2596 {
2597 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXTENSION_TAG);
2598 }
2599 break;
2600 }
2601 }
2602
2603 return ret;
2604 }
2605
CODE_SEGMENT(PAGE_DD_CODE)2606 CODE_SEGMENT(PAGE_DD_CODE)
2607 NVT_STATUS NvTiming_EDIDValidation (NvU8 *pEdid, NvU32 length, NvBool bIsStrongValidation)
2608 {
2609 if (NvTiming_EDIDValidationMask(pEdid, length, bIsStrongValidation) != 0) {
2610 return NVT_STATUS_ERR;
2611 } else {
2612 return NVT_STATUS_SUCCESS;
2613 }
2614 }
2615
2616 // Function Description: Get the first Detailed Timing Descriptor
2617 //
2618 // Parameters:
2619 // pEdidInfo: IN - pointer to parsed EDID
2620 // pT: OUT - pointer to where the DTD1 timing will be stored
2621 //
2622 // Return:
2623 // NVT_STATUS_SUCCESS: DTD1 was found in parsed EDID, pT is a valid result
2624 // NVT_STATUS_INVALID_PARAMETER: one or more parameter was invalid
2625 // NVT_STATUS_ERR: DTD1 was not found in parsed EDID, pT is invalid
CODE_SEGMENT(PAGE_DD_CODE)2626 CODE_SEGMENT(PAGE_DD_CODE)
2627 NVT_STATUS NvTiming_GetDTD1Timing (NVT_EDID_INFO * pEdidInfo, NVT_TIMING * pT)
2628 {
2629 NvU32 j;
2630
2631 // check param
2632 if (pEdidInfo == NULL || pT == NULL)
2633 {
2634 return NVT_STATUS_INVALID_PARAMETER;
2635 }
2636
2637 // find the PTM mode
2638 for (j = 0; j < pEdidInfo->total_timings; j++)
2639 {
2640 if (NVT_PREFERRED_TIMING_IS_DTD1(pEdidInfo->timing[j].etc.flag, pEdidInfo->timing[j].etc.status))
2641 {
2642 *pT = pEdidInfo->timing[j];
2643 return NVT_STATUS_SUCCESS;
2644 }
2645 }
2646
2647 // find DisplayID preferred
2648 for (j = 1; j < pEdidInfo->total_timings; j++)
2649 {
2650 if (NVT_PREFERRED_TIMING_IS_DISPLAYID(pEdidInfo->timing[j].etc.flag))
2651 {
2652 *pT = pEdidInfo->timing[j];
2653 return NVT_STATUS_SUCCESS;
2654 }
2655 }
2656
2657 // DTD1 should exist, but if it doesn't, return not found
2658 for (j = 0; j < pEdidInfo->total_timings; j++)
2659 {
2660 NvU32 data = pEdidInfo->timing[j].etc.status;
2661 if (NVT_IS_DTD1(data))
2662 {
2663 *pT = pEdidInfo->timing[j];
2664 return NVT_STATUS_SUCCESS;
2665 }
2666 }
2667
2668 // DTD1 should exist, but if it doesn't, return not found
2669 return NVT_STATUS_ERR;
2670 }
2671
2672 // Description: Parses a VTB extension block into its associated timings
2673 //
2674 // Parameters:
2675 // pEdidExt: IN - pointer to the beginning of the extension block
2676 // pInfo: IN - The original block information, including the
2677 // array of timings.
2678 //
2679 // NOTE: this function *really* should be in its own separate file, but a certain DVS test
2680 // uses cross build makefiles which do not allow the specification of a new file.
CODE_SEGMENT(PAGE_DD_CODE)2681 CODE_SEGMENT(PAGE_DD_CODE)
2682 void parseVTBExtension(NvU8 *pEdidExt, NVT_EDID_INFO *pInfo)
2683 {
2684 NvU32 i;
2685 VTBEXTENSION *pExt = (VTBEXTENSION *)pEdidExt;
2686 NvU32 count;
2687 NvU32 bytes;
2688 NVT_TIMING newTiming;
2689
2690 // Null = bad idea
2691 if (pEdidExt == NULL)
2692 {
2693 return;
2694 }
2695
2696 // Sanity check for VTB extension block
2697 if (pExt->tag != NVT_EDID_EXTENSION_VTB ||
2698 pExt->revision == NVT_VTB_REV_NONE)
2699 {
2700 return;
2701 }
2702
2703 // Sanity check - ensure that the # of descriptor does not exceed
2704 // byte size
2705 count = (NvU32)sizeof(EDID_LONG_DISPLAY_DESCRIPTOR) * pExt->num_detailed
2706 + (NvU32)sizeof(EDID_CVT_3BYTE_BLOCK) * pExt->num_cvt
2707 + (NvU32)sizeof(NvU16) * pExt->num_standard;
2708 if (count > NVT_VTB_MAX_PAYLOAD)
2709 {
2710 return;
2711 }
2712
2713 count = 0;
2714 bytes = 0;
2715
2716 // Process Detailed Timings
2717 for (i = 0; i < pExt->num_detailed; i++)
2718 {
2719 NVMISC_MEMSET(&newTiming, 0, sizeof(newTiming));
2720
2721 if (parseEdidDetailedTimingDescriptor((NvU8 *)(pExt->data + bytes),
2722 &newTiming) == NVT_STATUS_SUCCESS)
2723 {
2724 newTiming.etc.name[39] = '\0';
2725 newTiming.etc.status = NVT_STATUS_EDID_VTB_EXT_DTDn(++count);
2726
2727 if (!assignNextAvailableTiming(pInfo, &newTiming))
2728 {
2729 break;
2730 }
2731
2732 bytes += (NvU32)(sizeof(EDID_LONG_DISPLAY_DESCRIPTOR));
2733 }
2734 }
2735
2736 // Process CVT Timings
2737 for (i = 0; i < pExt->num_cvt; i++)
2738 {
2739 parseEdidCvt3ByteDescriptor((NvU8 *)(pExt->data + bytes), pInfo, &count);
2740
2741 bytes += (NvU32)sizeof(EDID_CVT_3BYTE_BLOCK);
2742 }
2743
2744 // Process Standard Timings
2745 for (i = 0; i < pExt->num_standard; i++)
2746 {
2747 NVMISC_MEMSET(&newTiming, 0, sizeof(newTiming));
2748
2749 parseEdidStandardTimingDescriptor(*(NvU16 *)(pExt->data + bytes),
2750 pInfo, count, &newTiming);
2751 newTiming.etc.name[39] = '\0';
2752 newTiming.etc.status = NVT_STATUS_EDID_VTB_EXT_STDn(++count);
2753
2754 if (!assignNextAvailableTiming(pInfo, &newTiming))
2755 {
2756 break;
2757 }
2758
2759 bytes += (NvU32)sizeof(NvU16);
2760 }
2761 }
2762
CODE_SEGMENT(PAGE_DD_CODE)2763 CODE_SEGMENT(PAGE_DD_CODE)
2764 static int IsPrintable(NvU8 c)
2765 {
2766 return ((c >= ' ') && (c <= '~'));
2767 }
2768
CODE_SEGMENT(PAGE_DD_CODE)2769 CODE_SEGMENT(PAGE_DD_CODE)
2770 static int IsWhiteSpace(NvU8 c)
2771 {
2772 // consider anything unprintable or single space (ASCII 32)
2773 // to be whitespace
2774 return (!IsPrintable(c) || (c == ' '));
2775 }
2776
CODE_SEGMENT(PAGE_DD_CODE)2777 CODE_SEGMENT(PAGE_DD_CODE)
2778 static void RemoveTrailingWhiteSpace(NvU8 *str, int len)
2779 {
2780 int i;
2781
2782 for (i = len; (i >= 0) && IsWhiteSpace(str[i]); i--)
2783 {
2784 str[i] = '\0';
2785 }
2786 }
2787
CODE_SEGMENT(PAGE_DD_CODE)2788 CODE_SEGMENT(PAGE_DD_CODE)
2789 static void RemoveNonPrintableCharacters(NvU8 *str)
2790 {
2791 int i;
2792
2793 // Check that all characters are printable.
2794 // If not, replace them with '?'
2795 for (i = 0; str[i] != '\0'; i++)
2796 {
2797 if (!IsPrintable(str[i]))
2798 {
2799 str[i] = '?';
2800 }
2801 }
2802 }
2803
2804 /**
2805 * @brief Assigns this timing to the next available slot in pInfo->timing[] if
2806 * possible.
2807 * @param pInfo EDID struct containing the parsed timings
2808 * @param pTiming New timing to be copied into pInfo->timing[]
2809 */
CODE_SEGMENT(PAGE_DD_CODE)2810 CODE_SEGMENT(PAGE_DD_CODE)
2811 NvBool assignNextAvailableTiming(NVT_EDID_INFO *pInfo,
2812 const NVT_TIMING *pTiming)
2813 {
2814 if (pInfo == NULL) return NV_TRUE;
2815
2816 // Don't write past the end of
2817 // pInfo->timing[NVT_EDID_MAX_TOTAL_TIMING]
2818 if (pInfo->total_timings >= COUNT(pInfo->timing)) {
2819 return NV_FALSE;
2820 }
2821
2822 pInfo->timing[pInfo->total_timings++] = *pTiming;
2823 return NV_TRUE;
2824 }
2825
2826 /**
2827 * @brief Return the nth highest priority index based on the different SVR
2828 * @param svr Short Video Reference
2829 */
CODE_SEGMENT(PAGE_DD_CODE)2830 CODE_SEGMENT(PAGE_DD_CODE)
2831 NvU8 getHighestPrioritySVRIdx(const NVT_EDID_CEA861_INFO *pExt861)
2832 {
2833 // In general, sink shall define the first one timing sequence
2834 NvU8 kth = 1;
2835 NvU8 i = 0;
2836
2837 for (i = 0; i < pExt861->total_svr; i++)
2838 {
2839 NvU8 svr = pExt861->svr_vfpdb[i];
2840
2841 // Reserved
2842 if (svr == 0 || svr == 128 || (svr >= 176 && svr <= 192) || svr == 255)
2843 continue;
2844
2845 if (svr >= 129 && svr <= 144) return svr - 128; // Interpret as the Kth 18-byte DTD in both base0 and CTA block (for N = 1 to 16)
2846 else if (svr >= 145 && svr <= 160) return svr - 144; // Interpret as the Nth 20-byte DTD or 6- or 7-byte CVT-based descriptor. (for N = 1 to 16)
2847 else if (svr >= 161 && svr <= 175) return svr - 160; // Interpret as the video format indicated by the first VFD of the first VFDB with Frame Rates of Rate Index N (for N = 1 to 15)
2848 else if (svr == 254) return kth; // Interpret as the timing format indicated by the first code of the first T8VTDB (for N = 1)
2849 else // assign corresponding CTA format's timing from pre-defined CE timing table, EIA861B
2850 {
2851 // ( SVR >= 1 and SVR <= 127) and (SVR >= 193 and SVR <= 253) needs to handle it by client
2852 return svr;
2853 }
2854 }
2855
2856 return 0;
2857 }
2858
CODE_SEGMENT(PAGE_DD_CODE)2859 CODE_SEGMENT(PAGE_DD_CODE)
2860 NVT_STATUS NvTiming_GetProductName(const NVT_EDID_INFO *pEdidInfo,
2861 NvU8 *pProductName,
2862 const NvU32 productNameLength)
2863 {
2864 NvU32 i = 0, m = 0, n = 0;
2865
2866 if( pEdidInfo == NULL || pProductName == NULL )
2867 {
2868 return NVT_STATUS_INVALID_PARAMETER;
2869 }
2870
2871 for ( i = 0; i < NVT_EDID_MAX_LONG_DISPLAY_DESCRIPTOR; i++)
2872 {
2873 if (pEdidInfo->ldd[i].tag == NVT_EDID_DISPLAY_DESCRITPOR_DPN)
2874 {
2875 for(n = 0; n < NVT_EDID_LDD_PAYLOAD_SIZE && pEdidInfo->ldd[i].u.product_name.str[n] != 0x0; n++)
2876 {
2877 pProductName[m++] = pEdidInfo->ldd[i].u.product_name.str[n];
2878 if ((m + 1) >= productNameLength)
2879 {
2880 goto done;
2881 }
2882 }
2883 }
2884 }
2885 done:
2886 pProductName[m] = '\0'; //Ensure a null termination at the end.
2887
2888 RemoveTrailingWhiteSpace(pProductName, m);
2889 RemoveNonPrintableCharacters(pProductName);
2890
2891 return NVT_STATUS_SUCCESS;
2892 }
2893
CODE_SEGMENT(PAGE_DD_CODE)2894 CODE_SEGMENT(PAGE_DD_CODE)
2895 NvU32 NvTiming_CalculateEDIDCRC32(NvU8* pEDIDBuffer, NvU32 edidsize)
2896 {
2897 return calculateCRC32(pEDIDBuffer, edidsize);
2898 }
2899
2900 //Calculates EDID/DisplayID2 CRC after purging 'Week of Manufacture', 'Year of Manufacture',
2901 //'Product ID String' & 'Serial Number' from EDID
CODE_SEGMENT(PAGE_DD_CODE)2902 CODE_SEGMENT(PAGE_DD_CODE)
2903 NvU32 NvTiming_CalculateCommonEDIDCRC32(NvU8* pEDIDBuffer, NvU32 edidVersion)
2904 {
2905 NvU32 commonEDIDBufferSize = 0;
2906 NvU8 CommonEDIDBuffer[256];
2907 NvU32 edidBufferIndex = 0;
2908
2909 if(pEDIDBuffer==NULL)
2910 {
2911 return 0;
2912 }
2913
2914 // Transfer over the original EDID buffer
2915 NVMISC_MEMCPY(CommonEDIDBuffer, pEDIDBuffer, 256);
2916
2917 if ((pEDIDBuffer[0] & 0xF0) == 0x20)
2918 {
2919 /*
2920 typedef struct DisplayId2Struct
2921 {
2922 NvU8 bVersion; // 0x00
2923 NvU8 bSectionBytes; // 0x01 - section length, exclusive the five mandatory bytes.
2924 NvU8 bwPrimaryUseCase; // 0x02
2925 NvU8 bExtensionCount; // 0x03
2926 // 0x20 DisplayId2 Standalone always exists Product Identification data block
2927 NvU8 bProductIdtag; // 0x04
2928 NvU8 bPIDRevision; // 0x05
2929 NvU8 bPayloadByte; // 0x06
2930 NvU8 bManuId[3]; // 0x07-0x09
2931 NvU16 wProductId; // 0x0A-0x0B
2932 NvU32 dwSerialNum; // 0x0C-0x0F
2933 NvU16 wWeekandYear; // 0x10-0x11
2934 NvU8 SizeOfProductNameString; // 0x12
2935 } DISPLAY_ID2_FIXED_FORMAT;
2936 */
2937
2938 // Wipe out the Serial Number, Week of Manufacture, and Year of Manufacture or Model Year
2939 NVMISC_MEMSET(CommonEDIDBuffer + 0x0C, 0, 6);
2940
2941 // Wipe out the checksums
2942 CommonEDIDBuffer[CommonEDIDBuffer[1]+5/*mandatory bytes*/-1] = 0;
2943 CommonEDIDBuffer[0xFF] = 0;
2944
2945 // zero out any Produc Name in Prodcut Identification data block
2946 if (CommonEDIDBuffer[0x12] != 0)
2947 {
2948 NVMISC_MEMSET(CommonEDIDBuffer + 0x13, 0, CommonEDIDBuffer[0x12]);
2949 CommonEDIDBuffer[0x12] = 0;
2950 }
2951
2952 // displayId2 standalone uses 256 length sections
2953 commonEDIDBufferSize = 256;
2954 }
2955 else
2956 {
2957 // Wipe out the Serial Number, Week of Manufacture, and Year of Manufacture or Model Year
2958 NVMISC_MEMSET(CommonEDIDBuffer + 0x0C, 0, 6);
2959
2960 // Wipe out the checksums
2961 CommonEDIDBuffer[0x7F] = 0;
2962 CommonEDIDBuffer[0xFF] = 0;
2963
2964 // We also need to zero out any "EDID Other Monitor Descriptors" (http://en.wikipedia.org/wiki/Extended_display_identification_data)
2965 for (edidBufferIndex = 54; edidBufferIndex <= 108; edidBufferIndex += 18)
2966 {
2967 if (CommonEDIDBuffer[edidBufferIndex] == 0 && CommonEDIDBuffer[edidBufferIndex+1] == 0)
2968 {
2969 // Wipe this block out. It contains OEM-specific details that contain things like serial numbers
2970 NVMISC_MEMSET(CommonEDIDBuffer + edidBufferIndex, 0, 18);
2971 }
2972 }
2973
2974 // Check what size we should do the compare against
2975 commonEDIDBufferSize = 128;
2976 }
2977
2978 return NvTiming_CalculateEDIDCRC32(CommonEDIDBuffer, commonEDIDBufferSize);
2979 } // NvTiming_CalculateCommonEDIDCRC32
2980
2981 // Calculate the minimum and maximum v_rate and h_rate, as well as
2982 // maximum pclk; initialize with the range of values in the EDID mode
2983 // list, but override with what is in the range limit descriptor section.
2984 //
2985 // based on drivers/modeset.nxt/CODE/edid.c:EdidGetMonitorLimits() and
2986 // EdidBuildRangeLimits()
CODE_SEGMENT(PAGE_DD_CODE)2987 CODE_SEGMENT(PAGE_DD_CODE)
2988 NVT_STATUS NvTiming_CalculateEDIDLimits(NVT_EDID_INFO *pEdidInfo, NVT_EDID_RANGE_LIMIT *pLimit)
2989 {
2990 NvU32 i;
2991
2992 NVMISC_MEMSET(pLimit, 0, sizeof(NVT_EDID_RANGE_LIMIT));
2993
2994 // the below currently only supports 1.x EDIDs
2995 if ((pEdidInfo->version & 0xFF00) != 0x100)
2996 {
2997 return NVT_STATUS_ERR;
2998 }
2999
3000 pLimit->min_v_rate_hzx1k = ~0;
3001 pLimit->max_v_rate_hzx1k = 0;
3002 pLimit->min_h_rate_hz = ~0;
3003 pLimit->max_h_rate_hz = 0;
3004 pLimit->max_pclk_10khz = 0;
3005
3006 // find the ranges in the EDID mode list
3007 for (i = 0; i < pEdidInfo->total_timings; i++)
3008 {
3009 NVT_TIMING *pTiming = &pEdidInfo->timing[i];
3010 NvU32 h_rate_hz;
3011
3012 if (pLimit->min_v_rate_hzx1k > pTiming->etc.rrx1k)
3013 {
3014 pLimit->min_v_rate_hzx1k = pTiming->etc.rrx1k;
3015 }
3016 if (pLimit->max_v_rate_hzx1k < pTiming->etc.rrx1k)
3017 {
3018 pLimit->max_v_rate_hzx1k = pTiming->etc.rrx1k;
3019 }
3020
3021 h_rate_hz = axb_div_c(pTiming->pclk, 10000, (NvU32)pTiming->HTotal);
3022
3023 if (pLimit->min_h_rate_hz > h_rate_hz)
3024 {
3025 pLimit->min_h_rate_hz = h_rate_hz;
3026 }
3027 if (pLimit->max_h_rate_hz < h_rate_hz)
3028 {
3029 pLimit->max_h_rate_hz = h_rate_hz;
3030 }
3031
3032 if (pLimit->max_pclk_10khz < pTiming->pclk)
3033 {
3034 pLimit->max_pclk_10khz = pTiming->pclk;
3035 }
3036 }
3037
3038 // use the range limit display descriptor, if available: these
3039 // override anything we found in the EDID mode list
3040 for (i = 0; i < NVT_EDID_MAX_LONG_DISPLAY_DESCRIPTOR; i++)
3041 {
3042 if (pEdidInfo->ldd[i].tag == NVT_EDID_DISPLAY_DESCRIPTOR_DRL)
3043 {
3044 NVT_EDID_DD_RANGE_LIMIT *pRangeLimit = &pEdidInfo->ldd[i].u.range_limit;
3045 NvU32 max_pclk_10khz;
3046
3047 // {min,max}_v_rate is in hz
3048 if (pRangeLimit->min_v_rate != 0) {
3049 pLimit->min_v_rate_hzx1k = pRangeLimit->min_v_rate * 1000;
3050 }
3051 if (pRangeLimit->max_v_rate != 0) {
3052 pLimit->max_v_rate_hzx1k = pRangeLimit->max_v_rate * 1000;
3053 }
3054
3055 // {min,max}_h_rate is in khz
3056 if (pRangeLimit->min_h_rate != 0) {
3057 pLimit->min_h_rate_hz = pRangeLimit->min_h_rate * 1000;
3058 }
3059 if (pRangeLimit->max_h_rate != 0) {
3060 pLimit->max_h_rate_hz = pRangeLimit->max_h_rate * 1000;
3061 }
3062
3063 // EdidGetMonitorLimits() honored the pclk from the
3064 // modelist over what it found in the range limit
3065 // descriptor, so do the same here
3066 max_pclk_10khz = pRangeLimit->max_pclk_MHz * 100;
3067 if (pLimit->max_pclk_10khz < max_pclk_10khz) {
3068 pLimit->max_pclk_10khz = max_pclk_10khz;
3069 }
3070
3071 break;
3072 }
3073 }
3074
3075 return NVT_STATUS_SUCCESS;
3076 }
3077
3078 // Build a user-friendly name:
3079 //
3080 // * get the vendor name:
3081 // * use the 3 character PNP ID from the EDID's manufacturer ID field
3082 // * expand, if possible, the PNP ID using the PNPVendorIds[] table
3083 // * get the product name from the descriptor block(s)
3084 // * prepend the vendor name and the product name, unless the product
3085 // name already contains the vendor name
3086 // * if any characters in the string are outside the printable ASCII
3087 // range, replace them with '?'
3088
3089 #define tolower(c) (((c) >= 'A' && (c) <= 'Z') ? (c) + ('a'-'A') : (c))
3090
CODE_SEGMENT(PAGE_DD_CODE)3091 CODE_SEGMENT(PAGE_DD_CODE)
3092 void NvTiming_GetMonitorName(NVT_EDID_INFO *pEdidInfo,
3093 NvU8 monitor_name[NVT_EDID_MONITOR_NAME_STRING_LENGTH])
3094 {
3095 NvU8 product_name[NVT_EDID_MONITOR_NAME_STRING_LENGTH];
3096 const NvU8 *vendor_name;
3097 NVT_STATUS status;
3098 NvU32 i, j;
3099 NvBool prepend_vendor;
3100
3101 NVMISC_MEMSET(monitor_name, 0, NVT_EDID_MONITOR_NAME_STRING_LENGTH);
3102
3103 // get vendor_name: it is either the manufacturer ID or the PNP vendor name
3104 vendor_name = pEdidInfo->manuf_name;
3105
3106 for (i = 0; i < (sizeof(PNPVendorIds)/sizeof(PNPVendorIds[0])); i++)
3107 {
3108 if ((vendor_name[0] == PNPVendorIds[i].vendorId[0]) &&
3109 (vendor_name[1] == PNPVendorIds[i].vendorId[1]) &&
3110 (vendor_name[2] == PNPVendorIds[i].vendorId[2]))
3111 {
3112 vendor_name = (const NvU8 *) PNPVendorIds[i].vendorName;
3113 break;
3114 }
3115 }
3116
3117 // get the product name from the descriptor blocks
3118 status = NvTiming_GetProductName(pEdidInfo, product_name, sizeof(product_name));
3119
3120 if (status != NVT_STATUS_SUCCESS)
3121 {
3122 product_name[0] = '\0';
3123 }
3124
3125 // determine if the product name already includes the vendor name;
3126 // if so, do not prepend the vendor name to the monitor name
3127 prepend_vendor = NV_TRUE;
3128
3129 for (i = 0; i < NVT_EDID_MONITOR_NAME_STRING_LENGTH; i++)
3130 {
3131 if (vendor_name[i] == '\0')
3132 {
3133 prepend_vendor = NV_FALSE;
3134 break;
3135 }
3136
3137 if (tolower(product_name[i]) != tolower(vendor_name[i]))
3138 {
3139 break;
3140 }
3141 }
3142
3143 j = 0;
3144
3145 // prepend the vendor name to the monitor name
3146 if (prepend_vendor)
3147 {
3148 for (i = 0; (i < NVT_EDID_MONITOR_NAME_STRING_LENGTH) && (vendor_name[i] != '\0'); i++)
3149 {
3150 monitor_name[j++] = vendor_name[i];
3151 }
3152 }
3153
3154 // if we added the vendor name above, add a space between the
3155 // vendor name and the product name
3156 if ((j > 0) && (j < (NVT_EDID_MONITOR_NAME_STRING_LENGTH - 1)))
3157 {
3158 monitor_name[j++] = ' ';
3159 }
3160
3161 // append the product name to the monitor string
3162 for (i = 0; (i < NVT_EDID_MONITOR_NAME_STRING_LENGTH) && (product_name[i] != '\0'); i++)
3163 {
3164 if (j >= (NVT_EDID_MONITOR_NAME_STRING_LENGTH - 1))
3165 {
3166 break;
3167 }
3168 monitor_name[j++] = product_name[i];
3169 }
3170 monitor_name[j] = '\0';
3171
3172 RemoveTrailingWhiteSpace(monitor_name, j);
3173 RemoveNonPrintableCharacters(monitor_name);
3174 }
3175
CODE_SEGMENT(PAGE_DD_CODE)3176 CODE_SEGMENT(PAGE_DD_CODE)
3177 void updateHDMILLCDeepColorForTiming(NVT_EDID_INFO *pInfo, NvU32 index)
3178 {
3179 NVT_EDID_CEA861_INFO *p861Info = &pInfo->ext861;
3180 // NOTE: EDID and CEA861 does not have clear statement regarding this.
3181 // To be backward compatible with current Nvidia implementation, if not edid >= 1.4 and CEA block exists, follow color format declaration from CEA block.
3182 // update supported color space within each bpc
3183 // rgb 8bpc always supported
3184
3185 UPDATE_BPC_FOR_COLORFORMAT(pInfo->timing[index].etc.rgb444, 0, 1,
3186 pInfo->hdmiLlcInfo.dc_30_bit,
3187 pInfo->hdmiLlcInfo.dc_36_bit,
3188 0, pInfo->hdmiLlcInfo.dc_48_bit);
3189
3190 if (p861Info->basic_caps & NVT_CEA861_CAP_YCbCr_444)
3191 {
3192 // pHdmiLlc->dc_y444 assumed basic cap is set; when base cap is set, 8bpc yuv444 always supported
3193 UPDATE_BPC_FOR_COLORFORMAT(pInfo->timing[index].etc.yuv444, 0, 1,
3194 pInfo->hdmiLlcInfo.dc_y444 && pInfo->hdmiLlcInfo.dc_30_bit,
3195 pInfo->hdmiLlcInfo.dc_y444 && pInfo->hdmiLlcInfo.dc_36_bit,
3196 0, pInfo->hdmiLlcInfo.dc_y444 && pInfo->hdmiLlcInfo.dc_48_bit);
3197 }
3198 if (p861Info->basic_caps & NVT_CEA861_CAP_YCbCr_422)
3199 {
3200 // pHdmiLlc->dc_y444 assumed basic cap is set; when base cap is set, 8bpc yuv422 always supported
3201 // newer CEA861/HDMI specs suggest the base cap should support both or neither (Nvidia puts no limitations here)
3202 // HDMI1.4b spec Section 6.2.4 Color Depth Requirements states that YCbCr 4:2:2 format is 36-bit mode, which means 8, 10 and 12bpc output is supported as soon as there is enough bandwidth
3203 UPDATE_BPC_FOR_COLORFORMAT(pInfo->timing[index].etc.yuv422, 0, 1, 1, 1, 0, 0);
3204 }
3205 }
3206
3207 POP_SEGMENTS
3208